为了账号安全,请及时绑定邮箱和手机立即绑定

IdleHandler,页面启动优化神器

标签:
Android

webp

随着App的开发到了某个阶段必然会遇到一个需求,那就是优化页面的启动时间。

第一个问题:有什么方法可以去统计页面的启动时间呢?

adb logcat -s ActivityManager | grep "Displayed"

上面的命令行可用来进行查看。

第二个问题:启动时间是包括了哪些流程,是如何被计算出来的呢?

App启动主要经过如下几个流程

  1. Launch the process.

  2. Initialize the objects.

  3. Create and initialize the activity.

  4. Inflate the layout.

  5. 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绘制之后调用

webp

由这个思路我把自己负责的页面中的一些界面的绘制逻辑挪到了IdleHandler中,由于有LoadingView时间,我把Adapter的绑定也挪出去了。看下优化前后效果图 ,效果还是挺明显的;

webp

webp



作者:Android高级架构
链接:https://www.jianshu.com/p/14251c80967a


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消