MessageQueue之IdleHandler

北战南征 提交于 2020-01-09 04:21:03

​IdleHandler是什么?

IdleHandler是包含在MessageQueue类中的一个接口,内部只包含一个方法,在消息队列空闲(没有消息或者第一个需要处理的消息在将来执行)时被回调

public static interface IdleHandler {    // 当消息队列空闲时会被回调, 返回值表示是否会被重复执行    // 返回true,会在mIdleHandlers列表中保留,在下次空闲时还会被调用;    // 返回false,会从mIdleHandlers列表中删除,下次不在被调用    boolean queueIdle();}

mIdleHandlers是一个ArrayList,用于存放需要执行的IdleHandler

IdleHandler是怎么工作的?

IdleHandler的工作过程分为两步:

  1. 添加IdleHandler

  2. 执行IdleHandler

首先需要知道IdleHandler是如何储存的,在MessageQueue的变量定义部分可以找到如下代码

// Idler列表,保存着MessageQueue空闲时需要执行的idlers,生命周期和MessageQueue一致private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();// 待执行Idler列表,每次MessageQueue空闲时会被重新赋值private IdleHandler[] mPendingIdleHandlers;

这两个简单的数据结构是仅有的两个IdleHandler载体。

添加方式很简单,只是使用了List的add操作,调用addIdleHandler即可将需要执行的Idler添加进列表

public void addIdleHandler(@NonNull IdleHandler handler) {    if (handler == null) {        throw new NullPointerException("Can't add a null IdleHandler");    }    synchronized (this) {        mIdleHandlers.add(handler);    }}

 

IdleHandler的回调只有一处,就是在MessageQueue的next方法中

Message next() {    ...    int pendingIdleHandlerCount = -1; // -1 only during first iteration    ...    for (;;) {        ...        synchronized (this) {            ...            // 中间省略部分为查找可执行的message的逻辑            // 如果找到则返回该message            // 没有找到则继续向下执行            ...                        // 从这里往下为IdleHandler相关操作                        // 获取要运行的idlers数量.            // 如果是第一次空闲(即第一次进入for循环) && (消息队列为空 || 第一个要执行的message是在将来执行)            if (pendingIdleHandlerCount < 0                    && (mMessages == null || now < mMessages.when)) {                pendingIdleHandlerCount = mIdleHandlers.size();            }            if (pendingIdleHandlerCount <= 0) {                // 如果没有需要执行idle handler则继续轮询                mBlocked = true;                continue;            }            // 创建一个待执行的IdleHandler列表            if (mPendingIdleHandlers == null) {                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];            }            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);        }        // 执行idle handlers.        // 只在第一次空闲时会执行到下面的for循环,因为一旦执行完pendingIdleHandlerCount就被赋值为0        for (int i = 0; i < pendingIdleHandlerCount; i++) {            final IdleHandler idler = mPendingIdleHandlers[i];            mPendingIdleHandlers[i] = null; // 释放掉handler的引用            boolean keep = false;            try {                // 回调IdleHandler,执行queueIdle方法!!                keep = idler.queueIdle();            } catch (Throwable t) {                Log.wtf(TAG, "IdleHandler threw exception", t);            }            // 不需要重复执行的idler从列表中移除            if (!keep) {                synchronized (this) {                    mIdleHandlers.remove(idler);                }            }        }        // 重置为0,使上面的循环不会重复执行.        pendingIdleHandlerCount = 0;        ...    }}

上面省略了部分不太相关的代码,注释已经把IdleHandler的调用过程写的比较清楚了,简单总结就是,第一次找不到可执行message时执行IdleHandler;再找不到可执行message时,轮询查找message不再执行IdleHandler。

IdleHandler能用来干什么?

因为IdleHandler是利用MessageQueue的空闲时间时间来工作的,所以一些不想对app性能产生影响的操作就可以交个IdleHandler来做,比如ActivityThread中的GC操作就是使用IdleHandler执行的。

当然我们也可以利用IdleHandler在主线程把一些工作提前,优化体验,更多使用方法将继续探索。


                                                                           欢迎关注公众号:从技术到艺术

                                                              

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!