Handler系列——IdleHandler(五)

什么是IdleHandler?

当MessageQueue为空或者目前没有需要执行的Message时会回调的接口对象。
IdleHandler 被定义在 MessageQueue 中,它看起来好像是个Handler,其实只是一个有单方法的接口,也称为函数型接口:

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

在MessageQueue中有一个List存储了IdleHandler对象,当MessageQueue没有需要被执行的Message时就会遍历回调所有的IdleHandler。所以IdleHandler主要用于在消息队列空闲的时候处理一些轻量级的工作。

调用

IdleHandler的调用是在next方法中:

Message next() {
    // 如果looper已经退出了,这里就返回null
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }
 
    // IdleHandler的数量
    int pendingIdleHandlerCount = -1; 
    // 阻塞时间
    int nextPollTimeoutMillis = 0;
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }
        // 阻塞对应时间 
        nativePollOnce(ptr, nextPollTimeoutMillis);
  		// 对MessageQueue进行加锁,保证线程安全
        synchronized (this) {
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            if (msg != null && msg.target == null) {
                // 同步屏障,找到下一个异步消息
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                if (now < msg.when) {
                    // 下一个消息还没开始,等待两者的时间差
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // 获得消息且现在要执行,标记MessageQueue为非阻塞
                    mBlocked = false;
                    // 一般只有异步消息才会从中间拿走消息,同步消息都是从链表头获取
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    msg.markInUse();
                    return msg;
                }
            } else {
                // 没有消息,进入阻塞状态
                nextPollTimeoutMillis = -1;
            }
 
            // 当调用Looper.quitSafely()时候执行完所有的消息后就会退出
            if (mQuitting) {
                dispose();
                return null;
            }
 
 			// 重点!!
            // 当队列中的消息用完了或者都在等待时间延迟执行同时给pendingIdleHandlerCount<0
            // 给pendingIdleHandlerCount赋值MessageQueue中IdleHandler的数量
            if (pendingIdleHandlerCount < 0
                    && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            // 没有需要执行的IdleHanlder直接continue
            if (pendingIdleHandlerCount <= 0) {
                // 执行IdleHandler,标记MessageQueue进入阻塞状态
                mBlocked = true;
                continue;
            }
 
            // 把List转化成数组类型
            if (mPendingIdleHandlers == null) {
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
            }
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }
 
        // 执行IdleHandler
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null; // 释放IdleHandler的引用
            boolean keep = false;
            try {
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf(TAG, "IdleHandler threw exception", t);
            }
            // 如果返回false,则把IdleHanlder移除
            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }
 
        // 最后设置pendingIdleHandlerCount为0,防止再执行一次
        pendingIdleHandlerCount = 0;
 
        // 当在执行IdleHandler的时候,可能有新的消息已经进来了
        // 所以这个时候不能阻塞,要回去循环一次看一下
        nextPollTimeoutMillis = 0;
    }
}

代码逻辑大概如下:

  1. 当调用next方法的时候,会给pendingIdleHandlerCount赋值为-1
  2. 如果队列中没有需要处理的消息的时候,就会判断pendingIdleHandlerCount是否<0,如果是则把存储IdleHandler的list的长度mIdleHandlers.size()赋值给pendingIdleHandlerCount
  3. 把list中的所有IdleHandler放到数组中。这一步是为了不让在执行IdleHandler的时候List被插入新的IdleHandler,造成逻辑混乱
  4. 然后遍历整个数组执行所有的IdleHandler
  5. 最后给pendingIdleHandlerCount赋值为0。然后再回去看一下这个期间有没有新的消息插入。因为pendingIdleHandlerCount的值为0不是-1,所以IdleHandler只会在空闲的时候执行一次
  6. 同时注意,如果IdleHandler返回了false,那么执行一次之后就被丢弃了。

总结

IdleHandler是一个回调接口,可以通过MessageQueueaddIdleHandler添加实现类。当MessageQueue中的任务暂时处理完了(没有新任务或者下一个任务延时在之后),这个时候会回调这个接口,返回false,那么就会移除它,返回true就会在下次message处理完了的时候继续回调。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值