在应用层,普通APP启动过程大致如下:
静态代码块/构造函数
onCreate()方法
静态代码段/构造函数
消息队列第一次循环:onCreate(),通过setContentView()解析、加载XML
消息队列第二次循环:被动的调用Choreographerd中的FrameDisplayEventRecevier的run()进行实际绘制
1.尽快显示DecoView(Main Thread)(显示Theme中定义的ActionBar、背景等)
2.尽快显示xml中的静态View(Main Thread)(显示xml的布局)
3.加载第三方黑盒SDK(Main Thread)
4.进行网络、图片等框架的构造(Main Thread)
5.通过框架进行业务请求(Gson/OkHttp等 Worker Thread),并更新View
不建议在Application中初始化耗时任务,它将直接导致白屏
本部分可以提高上文1、2、3的用户体验
DecoView的优先级比setContentView
的优先级高,所以可以让DecoView显示一个伪启动背景界面,而不是白屏黑屏或者没界面甩锅给手机厂商,让用户感受到App正在加载是一个好的选择。
绘制一个App启动的草图,如下,一个是Toolbar
、一个是背景
-
-
设置windowBackground
在启动时先加载了伪背景,然后才加载了真正的View元素
最终可以让用户觉得“提高”了0.1~0.2s的速度
此部分适用于解析、处理、绘制静态xml时的优化
xml布局优化是老生常谈的话题了,本质是减少无谓的绘制,网上面试宝典很多,这里就也不介绍了。解决方法如下:
1.使用Include,Merge,viewStub简化布局
2.简单布局使用线性布局,复杂布局时使用相对布局,layer-list降低树的层级
3.使用gone标签可以跳过绘制
4.被遮挡的view避免重复绘制
本部分不能压缩总时间,只是将耗时操作移动到后面而已,可以让白屏时间减少0.2~0.3s(取决于框架数量)
在onCreate()的最后,加入post操作,即可实现在绘制xmlView完成后再进行非UI的耗时操作
getWindow().getDecorView().post(new Runnable()){
@Override
public void run()
//加载Application中的框架 40+ms
GlobalContext.startThirdFrameWork();
//构建网络框架 120ms
repo = SquareUtils.getRetrofit(URL).create(GithubService.class);
//进行ssl库的初始化请求 40+ms
onRefresh();
}
});
在xml被inflate后,需要通过mDecoView.addView(xmlView)
进行添加
addView最终调用ViewRootImpl
的方法scheduleTraversals()
,进行了消息队列的优先独占操作
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
接着调用doTraversal()
释放
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
SyncBarrier拥有消息队列的独占性,当使用SyncBarrier
时,后面的消息将被阻塞,这样在主线程中就有更多的CPU时间可以分给WMS进行绘图了。在View绘制完成后,解除SyncBarrier后才会调用我们在上文Post的耗时框架加载任务,这样就实现了延迟加载。
此部分真的可以压缩启动时间,但是对SDK线程安全有一定的要求,在黑盒SDK下容易出现问题
下文复用了OkHttp中的单例Worker线程池,节省了0.16s的启动时间
SquareUtils.getDispatcher().executorService().execute(new Runnable() {
@Override
public void run() {
Log.d(TAG, "run: " + System.currentTimeMillis());
//42ms
GlobalContext.startThirdFrameWork();
//120ms
repo = SquareUtils.getRetrofit(DanbooruAPI.KONACHAN).create(DanbooruAPI.class);
runOnUiThread(new Runnable() {
@Override
public void run() {
//40ms
onRefresh();
}
});
}
});
经过测试,混淆在一定程度上可以提高速度,属于免费的性能提升,但是不是非常明显,大概只有100ms
混淆后要记得测试
通过上述方法,可以压榨0.3~0.6s的时间,让用户能够更快的启动APP