内容简介:随着App的开发到了某个阶段必然会遇到一个需求,那就是优化页面的启动时间。第一个问题:有什么方法可以去统计页面的启动时间呢?上面的命令行可用来进行查看。
随着App的开发到了某个阶段必然会遇到一个需求,那就是优化页面的启动时间。
第一个问题:有什么方法可以去统计页面的启动时间呢?
adb logcat -s ActivityManager | grep "Displayed" 复制代码
上面的命令行可用来进行查看。
第二个问题:启动时间是包括了哪些流程,是如何被计算出来的呢?
App启动主要经过如下几个流程
- Launch the process.
- Initialize the objects.
- Create and initialize the activity.
- Inflate the layout.
- Draw your application for the first time.
最末尾的步骤5是绘制你的界面。所以完整的启动时间是要到绘制完成为止。
那么绘制界面对应的是什么时候呢?一般我们开发,最晚能被回调的是在onResume方法,那么onResume方法是在绘制之后还是之前呢?
no code no truth
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) { //省略部分代码 r = performResumeActivity(token, clearHide, reason); //省略部分代码 if (a.mVisibleFromClient) { if (!a.mWindowAdded) { a.mWindowAdded = true; wm.addView(decor, l); 复制代码
看上面的代码,就先放结论了。
在performResumeActivity 中进行了onResume的回调,在wm.addView 中进行了绘制,因此onResume的方法是在绘制之前,在onResume中做一些耗时操作都会影响启动时间。
下面就剥一下onResume的逻辑,绘制的有兴趣可以自己看源码。 首先performResumeActivity中会调用r.activity.performResume();
public final ActivityClientRecord performResumeActivity(IBinder token, boolean clearHide, String reason) { //省略部分代码 try { r.activity.onStateNotSaved(); r.activity.mFragments.noteStateNotSaved(); checkAndBlockForNetworkAccess(); if (r.pendingIntents != null) { deliverNewIntents(r, r.pendingIntents); r.pendingIntents = null; } if (r.pendingResults != null) { deliverResults(r, r.pendingResults); r.pendingResults = null; } r.activity.performResume(); //省略部分代码 } } 复制代码
然后在performResume中调用了 mInstrumentation.callActivityOnResume(this);
final void performResume() { //省略部分代码 mInstrumentation.callActivityOnResume(this); //省略部分代码 } 复制代码
最后在callActivityOnResume 调用了onResume
public void callActivityOnResume(Activity activity) { activity.mResumed = true; activity.onResume(); //省略代码 } 复制代码
到了此处就算真正调用到了onResume的方法。
既然知道了onResume中做的操作会影响到启动时间,那么就有一个优化启动时间的思路了。
思路
把在onResume以及其之前的调用的但非必须的事件(如某些界面View的绘制)挪出来找一个时机(即绘制完成以后)去调用。那样启动时间自然就缩短了。但是整体做的事并没有明显变化。那么这个时机是什么呢?
IdleHandler
看下IdleHandler的源码
/** * Callback interface for discovering when a thread is going to block * waiting for more messages. */ public static interface IdleHandler { /** * Called when the message queue has run out of messages and will now * wait for more. Return true to keep your idle handler active, false * to have it removed. This may be called if there are still messages * pending in the queue, but they are all scheduled to be dispatched * after the current time. */ boolean queueIdle(); } 复制代码
从这个源码可知道,IdleHandler即在looper里面的message处理完了的时候去调用,这不就是我们onResume调用完了以后的时机么。
来一张图说明一下,明显的IdleHandler在onResume以及performTraversals绘制之后调用
由这个思路我把自己负责的页面中的一些界面的绘制逻辑挪到了IdleHandler中,由于有LoadingView时间,我把Adapter的绑定也挪出去了。看下优化前后效果图 效果还是挺明显的。
参考资料
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Web Applications (Hacking Exposed)
Joel Scambray、Mike Shema / McGraw-Hill Osborne Media / 2002-06-19 / USD 49.99
Get in-depth coverage of Web application platforms and their vulnerabilities, presented the same popular format as the international bestseller, Hacking Exposed. Covering hacking scenarios across diff......一起来看看 《Web Applications (Hacking Exposed)》 这本书的介绍吧!