一、直奔主题
来自用户、测试、产品、包括开发人员反馈:
app启动很慢,欢迎页停留太久或者启动黑屏等等,但有时候又不会。
起初一直不太重视,后来随着产品迭代更新,发现启动速度慢的问题越来越明显,已经影响到用户体验,甚至为了加快启动速度而要发一个升级包。于是决定优化一下启动速度,研究之后发现,还是有很多可以拿出来分享的;
二、基础知识
冷启动:
当后台不存在该应用的任何进程或者服务时,用户点击icon图标启动,我们称之为冷启动。
热启动
当后台存在该应用的进程或者服务时,用户点击icon图标启动,我们称之为热启动。
一般是用户按了home键回到桌面,或者返回键没有杀进程,或者app本身做了进程重启的机制。
启动组成时间
我们主要优化冷启动时间,只要冷启动时间优化了,热启动其实也跟着优化了。
冷启动时间分布如下:
application启动时间+欢迎页停留时间
按用户体验的启动时间应该是:
application启动时间+欢迎页停留时间+进入主页后显示主题的话时间;
三、优化点
1、Application的启动优化-兵家必争之地;
Application启动会经过attachBaseContext-->onCreate;
这两个方法不执行完是不会出现lanucher页面的;所以用户反馈点击图片后,要过一会才出现欢迎页的原因以下几个:
1、这两个方法太过费时导致的。
2、application的Theme被设置会透明的(系统一般默认有个白色或者黑色的)
3、对启动页不要做自定义动画,效果没有原声的好,会有一点点影响。
attachBaseContext优化
这个方法在没有MultiDex的app中或者没有特殊业务的app中一般是不用重写的,但是由于业务需要,我们的app需要集成multidex,导致我们需要在此方法里进行MultiDex.install操作,这个操作其实是耗时的,没办法优化,但是也不能让用户傻等.
(1)优化初次启动
我们知道5.0以下初次安装启动需要进行dexopt的过程,这个过程是非常耗时的,在一些比较低端的机子上甚至能到达20秒,而且只能在主UI线程进行,如果我们直接执行install的话,很有可能出现ANR,黑屏,等各种非常不好的体验,怎么办呢,我们可以绕过我们的主进程: 我们开启一个新的进程用于install操作,并弹出一个欢迎页;然后再我们的主线程一直检测是否安装完成,超时时间设置为30秒;完成之后弹出主进程的欢迎页面(注意:为了让用户无感知,这两个页面必须一模一样,且中间不能用过渡动画)。经过实践:基本上这套方案可以适用所有目前兼容的机型。
(2)Application Theme建议设置为透明的(处于用户体验的考虑)
onCreate优化
每次application启动或者重启的时候都会触发onCreate;如果这个方法耗时超过500ms的话,你可以很明显的感受到点击icon之后,欢迎页不会立刻展示出来。
然而不幸的是,很多第三方的组件,如友盟,百川等等都需要在此进行初始化,原因是防止进程被回收之后他们还有机会进行重新初始化而不影响业务。
原因上我们可以接受,但一旦初始化耗费时间多少完全无法控制,完全看第三方“良心”了,但即使在 我们既无法改变第三方初始化速度慢的问题,也不能将其从application移除的情况下,我们依然要优化启动速度,因为用户体验是在太重要。
迎难而上吧!
优化思路:最大的优化思路就是onCreate什么都不执行,先让欢迎页弹窗出来;这个想法初步很简单,也很好实现,然而存在几个问题:
(1)进程被回收重启后,如何重新初始化?
(2)通知栏推送后,进入到目的页面,如何防止因为没初始化导致的闪退或者功能异常?
(3)application oncreate什么都不做,那初始化放在哪里做呢;
只要这两个问题解决了,基本上application的优化就算完成了,怎么解决呢,我们采用了下面的办法 我们在application只干了一件事,而且几乎不费时,他就是:监听页面的生命周期:
registerActivityLifecycleCallbacks
这个方法可以让我们监听所有页面的生命周期,包括启动,可见,销毁等等,而启动的时候android本身带了一个参数 public void onActivityCreated(Activity activity, Bundle savedInstanceState);中的Bundle,如果Bundle不为空,说明是回收回来的,我们可以在这里进行重新初始化,而不影响其他功能;因此(1)(2)问题迎刃而解; 关于(3)的问题是正常流程问题,如果放在欢迎页初始化,是不妥的,并不是所有的入口都走欢迎页; 所以我们在application接收了一个初始化的事件,只要收到这个事件,就可以进行初始化,初始化完了之后,再发出初始化完成的通知; (其实这一步是为了优化欢迎页做的准备,继续往下看。)
application通过以上几步优化之后,就只剩下5.0以下dexopt和multidex.install消耗的时间优化的,要做到不执行Multi.install多个dex,只能自己动态实现dex的加载,也就是插件化,还有一段很长的路要走,继续往下说。
2、启动页启动优化-用户可见的第一感知
application优化完了以后,就会执行启动页的onCreate,我们发现oncreate一旦耗时,也会导致启动页有一顺气的卡顿,精益求精,我们把启动页的启动逻辑延迟初始化并通知application进行初始化,然后等待application初始化完成的事件之后,继续往下走,知道进入主页; 启动也的优化逻辑比较简单,只是纯业务的上的调整。
3、主页优化
主要优化onCreate即可。把可以放线程初始化的都放到线程里去。
经过以上几步优化之后,我们发现启动速度有了非常明显的提示,其实大部分的时候都花在了业务的整理和application启动的优化上边,比较容易出bug的地方是我们相当于改变了应该在appliation oncreate初始化方式,由于有些组件初始化是异步的,还是可能出现初始化未完成就被使用的情况,这需要业务上进行相关的处理。贴一组优化后的数据,效果很理想。
优化前:
application正常启动 耗时:1299
application延迟启动 耗时:4081
Welcome 启动 耗时:289
Tab启动 耗时:1143
优化后:
D/耗时统计: meiyou : application onCreate 耗时:3
D/耗时统计: meiyou : application initNeedAtApplication 耗时:190
D/耗时统计: meiyou : welcome oncreate耗时:89
D/WelcomeController: meiyou : welcome handleGo 耗时:324
D/耗时统计: meiyou : welcome initLogic 耗时:324
D/耗时统计: meiyou : MainActivity onCreate 耗时:136
D/耗时统计: meiyou : HomeFragment onCreate 耗时:72
总的来说,对于一个比较大型的app的启动逻辑还是蛮复杂的,有必要的话都需要整理并优化一下,欢迎大家吐槽,共勉。
文章转载自 开源中国社区 [http://www.oschina.net]