IdleHandler,页面启动优化神器

作者 : 开心源码 本文共5952个字,预计阅读时间需要15分钟 发布时间: 2022-05-12 共194人阅读

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

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

<pre style=”margin: 0px; padding: 0px; border: 0px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-weight: 400; font-stretch: inherit; font-size: 18px; line-height: inherit; font-family: inherit; vertical-align: baseline; word-break: break-word; color: rgb(93, 93, 93); letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;”>

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

<pre style=”margin: 0px; padding: 0px; border: 0px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-weight: 400; font-stretch: inherit; font-size: 18px; line-height: inherit; font-family: inherit; vertical-align: baseline; word-break: break-word; color: rgb(93, 93, 93); letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;”>

 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();

<pre style=”margin: 0px; padding: 0px; border: 0px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-weight: 400; font-stretch: inherit; font-size: 18px; line-height: inherit; font-family: inherit; vertical-align: baseline; word-break: break-word; color: rgb(93, 93, 93); letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;”>

 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);

<pre style=”margin: 0px; padding: 0px; border: 0px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-weight: 400; font-stretch: inherit; font-size: 18px; line-height: inherit; font-family: inherit; vertical-align: baseline; word-break: break-word; color: rgb(93, 93, 93); letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;”>

 final void performResume() { //省略部分代码 mInstrumentation.callActivityOnResume(this); //省略部分代码 }

最后在callActivityOnResume 调用了onResume

<pre style=”margin: 0px; padding: 0px; border: 0px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-weight: 400; font-stretch: inherit; font-size: 18px; line-height: inherit; font-family: inherit; vertical-align: baseline; word-break: break-word; color: rgb(93, 93, 93); letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;”>

 public void callActivityOnResume(Activity activity) { activity.mResumed = true; activity.onResume(); //省略代码 }

到了此处就算真正调用到了onResume的方法。

既然知道了onResume中做的操作会影响到启动时间,那么就有一个优化启动时间的思路了。

思路

把在onResume以及其之前的调用的但非必需的事件(如某些界面View的绘制)挪出来找一个时机(即绘制完成以后)去调用。那样启动时间自然就缩短了。但是整体做的事并没有显著变化。那么这个时机是什么呢?

IdleHandler

看下IdleHandler的源码

<pre style=”margin: 0px; padding: 0px; border: 0px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-weight: 400; font-stretch: inherit; font-size: 18px; line-height: inherit; font-family: inherit; vertical-align: baseline; word-break: break-word; color: rgb(93, 93, 93); letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;”>

 /** * 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的绑定也挪出去了。看下优化前后效果图 ,效果还是挺显著的;

Android技术交流QQ群;701740775。
本群提供免费的学习指导 资料视频像高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)等内容 以及免费的解答。不懂得问题都可以在本群提出来 ,之后还会有职业生涯规划以及面试指导

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » IdleHandler,页面启动优化神器

发表回复