应用启动流程总结:
①点击启动一个App,Launcher进程采用Binder IPC向ActivityManagerService发起startActivity请求;
②ActivityManagerService接收到请求后,向zygote进程发送创建进程的请求;
③Zygote进程fork出新的子进程,即App进程;
④App进程通过Binder IPC向sytem_server进程发起绑定Application请求;
⑤system_server进程在收到请求后,进行一系列准备工作后,再通过binder IPC向App进程发送scheduleLaunchActivity请求;
⑥App进程的binder线程(ApplicationThread)在收到请求后,通过handler向主线程发送LAUNCH_ACTIVITY消息;
⑦主线程在收到Message后,通过发射机制创建目标Activity,并回调Activity.onCreate()等方法。
从这里的应用启动过程来看,我们要对应用启动速度进行优化,能做的就是在application和launcherActivity的启动进行优化,即不能进行耗时操作。
冷启动、温启动、热启动概念
冷启动
冷启动指的是该应用程序在此之前没有被创建,发生在应用程序首次启动或者自上次被终止后的再次启动。简单的说就是app进程还没有,需要创建app的进程启动app。
比如开机后,点击屏幕的app图标启动应用。
冷启动的过程主要分为两步:
1)系统任务。加载并启动应用程序;显示应用程序的空白启动窗口;创建APP进程
2)APP进程任务。启动主线程;创建Activity;加载布局;屏幕布局;绘制屏幕
其实这不就是APP的启动流程嘛?所以冷启动是会完整走完一个启动流程的,从系统到进程。
温启动
温启动指的是App进程存在,但Activity可能因为内存不足被回收,这时候启动App不需要重新创建进程,只需要执行APP进程中的一些任务,比如创建Activity。
比如返回主页后,又继续使用其他的APP,时间久了或者打开的应用多了,之前应用的Activity有可能被回收了,但是进程还在。
所以温启动相当于执行了冷启动的第二过程,也就是APP进程任务,需要重新启动线程,Activity等。
热启动
热启动就是App进程存在,并且Activity对象仍然存在内存中没有被回收。
比如app被切到后台,再次启动app的过程。
所以热启动的开销最少,这个过程只会把Activity从后台展示到前台,无需初始化,布局绘制等工作。
那我们所要做的启动速度优化呢,就是对于冷启动这种情况进行的。
启动过程需要经过哪些生命周期方法呢?
-> Application 构造函数
-> Application.attachBaseContext()
-> Application.onCreate()
-> Activity 构造函数
-> Activity.setTheme()
-> Activity.onCreate()
-> Activity.onStart
-> Activity.onResume
-> Activity.onAttachedToWindow
-> Activity.onWindowFocusChanged
启动开始标识为Application.attachBaseContext(),启动结束的最后标识是LauncherActivity的onWindowFocusChanged方法调用完成。
1、Application的onCreate流程,对于大型的APP来说,通常会在这里做大量的通用组件的初始化操作;
建议:很多第三方SDK都放在Application初始化,我们可以放到用到的地方才进行初始化操作。
2、Activity的onCreate流程,特别是UI的布局与渲染操作,如果布局过于复杂很可能导致严重的启动性能问题;
App进程的创建等环节我们是无法主动控制的,可以优化的也就是Application、Activity创建以及回调等过程。
解决方案1 :添加一个默认的启动页的Theme能从现象解决这个问题,但是并没有从根本上解决启动慢的问题。
解决方案2:
Application中主要做了各种三方组件的初始化,参数设置,启动各种服务等;
对于过多的初始化任务,我们考虑以下优化方案:
1.考虑异步初始化三方组件,不阻塞主线程;
2.延迟部分三方组件的初始化;
启动耗时统计:
如果是本地调试的话,统计启动时间还是很简单的,通过命令行方式即可:
adb shell am start -w packagename/activity
WaitTime
返回从 startActivity 到应用第一帧完全显示这段时间. 就是总的耗时,包括前一个应用 Activity pause 的时间和新应用启动的时间;
ThisTime
表示一连串启动 Activity 的最后一个 Activity 的启动耗时;
TotalTime
表示新应用启动的耗时,包括新进程的启动和 Activity 的启动;
TotalTime是我们需要关注的应用启动的真正时长。
开启使用CPU profiler追踪启动过程:
开启对程序追踪模式,启动程序,得到追踪的结果:
这里得到追踪的启动过程各个方法调用的时长,针对耗时较长的方法进行分析和优化,解决耗时问题。
CPU Profile各查看方法比较:
找到这些布局加载耗时,或者第三放库初始化,或者我们自己的方法比较耗时,主要的处理思路就是合理的使用异步初始化、延迟初始化、懒加载机制。