美文网首页
Android 开源框架 06 --- Android Idle

Android 开源框架 06 --- Android Idle

作者: 沪漂意哥哥 | 来源:发表于2022-05-18 11:25 被阅读0次

    介绍

    IdleHandler 是 MessageQueue 内定义的一个接口,一般可用于做性能优化。当消息队列内没有需要立即执行的 message 时,会主动触发 IdleHandler 的 queueIdle 方法。返回值为 false,即只会执行一次;返回值为 true,即每次当消息队列内没有需要立即执行的消息时,都会触发该方法。

    public final class MessageQueue {
       public static interface IdleHandler {
           boolean queueIdle();
       }
    }
    

    使用方式

    通过获取 looper 对应的 MessageQueue 队列注册监听。

    Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
       @Override
       public boolean queueIdle() {
           // doSomething()
           return false;
       }
    });
    

    源码解析

    IdleHandler 的执行源码很短。

    Message next() {
       // 隐藏无关代码...
       int pendingIdleHandlerCount = -1; // -1 only during first iteration
       int nextPollTimeoutMillis = 0;
       for (; ; ) {
           // 隐藏无关代码...
           // If first time idle, then get the number of idlers to run.
           // Idle handles only run if the queue is empty or if the first message
           // in the queue (possibly a barrier) is due to be handled in the future.
           if (pendingIdleHandlerCount < 0
                   && (mMessages == null || now < mMessages.when)) {
               pendingIdleHandlerCount = mIdleHandlers.size();
           }
           if (pendingIdleHandlerCount <= 0) {
               // No idle handlers to run.  Loop and wait some more.
               mBlocked = true;
               continue;
           }
           if (mPendingIdleHandlers == null) {
               mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
           }
           mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
       }
       // Run the idle handlers.
       // We only ever reach this code block during the first iteration.
       for (int i = 0; i < pendingIdleHandlerCount; i++) {
           final IdleHandler idler = mPendingIdleHandlers[i];
           mPendingIdleHandlers[i] = null; // release the reference to the handler
           boolean keep = false;
           try {
               keep = idler.queueIdle();
           } catch (Throwable t) {
               Log.wtf(TAG, "IdleHandler threw exception", t);
           }
           if (!keep) {
               synchronized (this) {
                   mIdleHandlers.remove(idler);
               }
           }
       }
       // Reset the idle handler count to 0 so we do not run them again.
       pendingIdleHandlerCount = 0;
       // While calling an idle handler, a new message could have been delivered
       // so go back and look again for a pending message without waiting.
       nextPollTimeoutMillis = 0;
    }
    

    1.在 MessageQueue 里 next 方法的 for 死循环内,获取 mIdleHandlers 的数量 pendingIdleHandlerCount;
    2.通过 mMessages == null || now < mMessages.when 判断当前消息队列为空或者目前没有需要执行的消息时,给 pendingIdleHandlerCount 赋值;
    3.当数量大于 0,遍历取出数组内的 IdleHandler,执行 queueIdle() ;
    4.返回值为 false 时,主动移除监听 mIdleHandlers.remove(idler);

    使用场景

    1.如果启动的 Activity、Fragment、Dialog 内含有大量数据和视图的加载,导致首次打开时动画切换卡顿或者一瞬间白屏,可将部分加载逻辑放到 queueIdle() 内处理。例如引导图的加载和弹窗提示等;
    2.系统源码中 ActivityThread 的 GcIdler,在某些场景等待消息队列暂时空闲时会尝试执行 GC 操作;
    3.系统源码中 ActivityThread 的 Idler,在 handleResumeActivity() 方法内会注册 Idler(),等待 handleResumeActivity 后视图绘制完成,消息队列暂时空闲时再调用 AMS 的 activityIdle 方法,检查页面的生命周期状态,触发 activity 的 stop 生命周期等。
    这也是为什么我们 BActivity 跳转 CActivity 时,BActivity 生命周期的 onStop() 会在 CActivity 的 onResume() 后。
    4.一些第三方框架 Glide 和 LeakCanary 等也使用到 IdleHandler,感兴趣的朋友可以看看源码;

    相关文章

      网友评论

          本文标题:Android 开源框架 06 --- Android Idle

          本文链接:https://www.haomeiwen.com/subject/okfmurtx.html