Android冷启动详解

  • 冷启动:
  • 热启动:
  • APP冷启动详解
  • 冷启动优化


本文主要讲Android app 冷、热启动流程,已经启动优化。

冷启动:

当应用启动时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用,这个启动方式就叫做冷启动(后台不存在该应用进程)。

冷启动因为系统会重新创建一个新的进程分配给它,所以会先创建和初始化Application类,再创建和初始化MainActivity类(包括一系列的测量、布局、绘制),最后显示在界面上。

简单一句话:app被完全杀死后,新启动的过程。

热启动:

当应用已经被打开,但是按Home键回到桌面或按功能键切换到其他程序,再重新打开该app时,这个方式叫做热启动(后台已经存在该应用进程)。

热启动因为会从已有的进程中来启动,所以热启动就不会走Application这步了,而是直接走MainActivity(包括一系列的测量、布局、绘制),所以热启动的过程只需要创建和初始化一个MainActivity就行了,而不必创建和初始化Application

简单一句话:后台程序重新拉起的过程。


APP冷启动详解

冷启动的流程

Activity的启动流程图(放大可查看)如下所示:


整个流程涉及的主要角色有:

  • Instrumentation: 监控应用与系统相关的交互行为。
  • AMS:组件管理调度中心,什么都不干,但是什么都管。
  • ActivityStarter:Activity启动的控制器,处理Intent与Flag对Activity启动的影响,具体说来有:1 寻找符合启动条件的Activity,如果有多个,让用户选择;2 校验启动参数的合法性;3 返回int参数,代表Activity是否启动成功。
  • ActivityStackSupervisior:这个类的作用你从它的名字就可以看出来,它用来管理任务栈。
  • ActivityStack:用来管理任务栈里的Activity。
  • ActivityThread:最终干活的人,是ActivityThread的内部类,Activity、Service、BroadcastReceiver的启动、切换、调度等各种操作都在这个类里完成。

注:这里单独提一下ActivityStackSupervisior,这是高版本才有的类,它用来管理多个ActivityStack,早期的版本只有一个ActivityStack对应着手机屏幕,后来高版本支持多屏以后,就
有了多个ActivityStack,于是就引入了ActivityStackSupervisior用来管理多个ActivityStack。

整个流程主要涉及四个进程:

  • 调用者进程,如果是在桌面启动应用就是Launcher应用进程。
  • ActivityManagerService等所在的System Server进程,该进程主要运行着系统服务组件。
  • Zygote进程,该进程主要用来fork新进程。
  • 新启动的应用进程,该进程就是用来承载应用运行的进程了,它也是应用的主线程(新创建的进程就是主线程),处理组件生命周期、界面绘制等相关事情。

有了以上的理解,整个流程可以概括如下:

1. 点击桌面应用图标,Launcher进程将启动Activity(MainActivity)的请求以Binder的方式发送给了AMS。
2. AMS接收到启动请求后,交付ActivityStarter处理Intent和Flag等信息,然后再交给ActivityStackSupervisior/ActivityStack
处理Activity进栈相关流程。同时以Socket方式请求Zygote进程fork新进程。
3. Zygote接收到新进程创建请求后fork出一个新进程(App主进程)给应用。并在主进程中创建ActivityThread对象和开启Looper消息循环,开始处理创建Activity。
4. 在创建Activity之前,如果自定义了Application类,会创建和初始化Application类。
5. ActivityThread利用ClassLoader去加载Activity、创建Activity实例,并回调Activity的onCreate()方法。这样便完成了Activity的启动。

注意⚠️:启动Activity时,会先创建Activity实例,然后加载主题样式Theme中的windowBackground等属性设置给MainActivity以及配置Activity层级上的一些属性、再inflate布局、当onCreate/onStart/onResume方法都走完了后最后才进行contentView的measure/layout/draw显示在界面上

Application构造方法 –> attachBaseContext() –> onCreate –>  
Activity构造方法 –> onCreate() –> 配置主题中的背景等操作 –> 
onStart() –> onResume() –> 测量、布局、绘制显示

冷启动优化

冷启动的优化主要是视觉上的优化,解决白屏问题,提高用户体验,所以通过上面冷启动的过程。能做的优化如下:

  • 减少 onCreate()方法的工作量
  • 不要让 Application 参与业务的操作
  • 不要在 Application 进行耗时操作
  • 不要以静态变量的方式在 Application 保存数据
  • 减少布局的复杂度和层级
  • 减少主线程耗时

为什么冷启动会有白屏黑屏问题?

原因在于加载主题样式Theme中的windowBackground等属性,设置给MainActivity发生在inflate布局当onCreate/onStart/onResume方法之前,而windowBackground背景被设置成了白色或者黑色,所以我们进入app的第一个界面的时候会造成先白屏或黑屏一下再进入界面。

解决思路如下

1、 给他设置 windowBackground 背景跟启动页的背景相同,如果你的启动页是张图片那么可以直接给 windowBackground 这个属性设置该图片那么就不会有一闪的效果了

<style name="Splash_Theme" parent= "@android:style/Theme.NoTitleBar">
    <item name="android:windowBackground">@drawable/splash_bg</item>
    <item name="android:windowNoTitle"> true </item>
</style>`

2、 甩锅法。将windowBackground设置为透明,给人一种延迟启动的感觉。这样当用户点击桌面 APP icon 的时候,并不会"立即"进入APP,而且在桌面上停留一会,其实这时候APP已经是启动的了,只是我们心机的把Theme里的windowBackground 的颜色设置成透明的,强行把锅甩给了手机应用厂商(手机反应太慢了啦)

<style name="Splash_Theme" parent="@android:style/Theme.NoTitleBar">
    <item name="android:windowIsTranslucent"> true </item>
    <item name="android:windowNoTitle"> true </item>
</style>

3、 以上两种方法是在视觉上显得更快,但其实只是一种表象,让应用启动的更快,有一种思路,将 Application 中的不必要的初始化动作实现懒加载,比如,在SpashActivity 显示后再发送消息到 Application,去初始化,这样可以将初始化的动作放在后边,缩短应用启动到用户看到界面的时间。