本篇是我在项目中对应用启动时间优化的一个总结。同时也参考了其他大神的文章。主要针对没有设置广告引导页的Android应用,这种Android应用的启动时间一般都要求比较高。否则就会影响用户体验。
目录
1.安卓应用的启动方式。
安卓应用的启动方式分为冷启动和热启动两种。
1、冷启动:启动应用时,系统中不存在此应用的进程;需要系统先去创建一个新的进程分配给该应用。因为创建一个新的进程,所以会先初始化Application类,再初始化MainActivity类。这种启动方式就是冷启动。
2、热启动:启动应用时,系统中已有该应用的进程(如按back键、home键,该应用的进程是依然会保留在后台),不必创建和初始化Application,而是初始化MainActivity,这个方式叫热启动。
本篇只总结冷启动的优化。
2.应用冷启动的流程
在安卓系统上,应用在没有进程的情况下,应用的启动都是这样一个流程:当点击app的启动图标时,安卓系统会从Zygote进程中fork创建出一个新的进程分配给该应用,之后会依次创建和初始化Application类、创建MainActivity类、加载主题样式Theme中的windowBackground等属性设置给MainActivity以及配置Activity层级上的一些属性、再inflate布局、当onCreate/onStart/onResume方法都走完了后最后才进行contentView的measure/layout/draw显示在界面上,所以直到这里,应用的第一次启动才算完成,这时候我们看到的界面也就是所说的第一帧。
所以,总结一下,应用的冷启动流程如下:
Application——>attachBaseContext()——>onCreate()——>Activity——>onCreate()——>onStart()——>onResume()——>显示。
3.如何测试应用的启动时间
可以通过adb shell命令的方式进行测量,这种方法测量的最为精确,命令:
adb shell am start -W [packageName]/[packageName.MainActivity]
执行成功后将返回三个测量到的时间:
1、ThisTime:一般和TotalTime时间一样,除非在应用启动时开了一个透明的Activity预先处理一些事再显示出主Activity,这样将比TotalTime小。
2、TotalTime:应用的启动时间,包括创建进程+Application初始化+Activity初始化到界面显示。
3、WaitTime:一般比TotalTime大点,包括系统影响的耗时。
4.如何减少应用冷启动的耗时
针对冷启动的流程,主要采取以下策略:
1、优化Application,在Application的构造器方法、attachBaseContext()、onCreate()方法中不要进行耗时操作,耗时操作尽量放在异步线程中,采取Callable实现。
2、优化数据库初始化,数据库的初始化都是比较耗时的,所以放在主线程中会延迟应用的启动速度,还是需要放在异步线程中处理。
3、优化MainActivity,由于在获取到第一帧前,需要对contentView进行测量布局绘制操作,尽量减少布局的层次,通过StubView的延迟加载策略;尽量减少在onCreate()、onStart()、onResume方法中执行主线程逻辑,可以将必须在主线程执行的低优先级任务放到IdleHandler中执行。
5.相关的优化操作
5.1 使用StubView延迟加载策略
ViewStub 是一个轻量级的View,它一个看不见的,不占布局位置,占用资源非常小的控件。可以为ViewStub指定一个布局,在Inflate布局的时候,只有 ViewStub会被初始化,然后当ViewStub被设置为可见的时候,或是调用了ViewStub.inflate()的时候,ViewStub所指向的布局就会被Inflate和实例化,然后ViewStub的布局属性都会传给它所指向的布局。我们可以使用ViewStub来延迟加载某个布局。
5.2 使用IdleHandler执行必要的主线任务
android主线程looper是在ActivityThread.java的main函数实例化的, 主线程使用一个MessageQueue实例,当消息过多或者消息执行周期比较长就会造成UI卡顿。
IdleHandler的作用是监听到MessageQueue中空闲(即onResume()执行完,绘制完成以后)的时候会回调queueIdle()
,该方法返回一个boolean
值,如果为false
则执行完毕之后移除这条消息, 如果为true
则保留,等到下次空闲时会再次执行。
欢迎指出本文中的不足之处,然后大家一起讨论。