我们的在业务开发的过程中,可能会遇到这样子的情况,需要再 UI线程 空闲的时候,做一些操作,那应该怎样子实现呢?

MessageQueue.IdleHandler

MessageQueue 给我们提供了一个 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();

根据源码的注释我们可以知道,这是一个在消息队列的全部消息处理完成或者没有消息需要处理在阻塞的过程中等待新消息的时候调用的,其返回值决定了,是否需要保持这个监听。具体实现方式如下:

private static final String TAG = "MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Looper.myQueue().addIdleHandler(mKeepIdleHandler);
        Looper.myQueue().addIdleHandler(mOnlyOnceIdleHandler);
        findViewById(R.id.textView).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e(TAG, " 按钮被点击了 ");
    private MessageQueue.IdleHandler mKeepIdleHandler = new MessageQueue.IdleHandler() {
        @Override
        public boolean queueIdle() {
            Log.i(TAG, " mKeepIdleHandler queueIdle 被回调了 ");
            return true;
    private MessageQueue.IdleHandler mOnlyOnceIdleHandler = new MessageQueue.IdleHandler() {
        @Override
        public boolean queueIdle() {
            Log.i(TAG, "mOnlyOnceIdleHandler queueIdle 被回调了 ");
            return false;

实现自己的IdleHandler,并在queueIdle接口中返回true表明需要保持监听。在我们的demo运行起来之后,会看到LogCat有对应的输出:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yR8vYgJA-1575798965736)(media/15757986947143.jpg)]

可以看到,返回true的场景,会再之后UI线程空闲的时候,再次回调,但如果是返回false的场景,只会执行调用一次。

另外需要注意,这里的回调,并不是说,当前UI线程是空闲状态,就会一直不断回调,如果没有更多的消息输入,回调一次之后,需要等到再次有消息输入并处理完成之后,才会有另外一次的调用。具体原理可以从源码中看到。

  int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            nativePollOnce(ptr, nextPollTimeoutMillis);
            synchronized (this) {
                // 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.
                //首次遍历,原始值是-1,故进入
                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 MessageQueue.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 MessageQueue.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;

设置pendingIdleHandlerCount的默认值为-1,这个会在判断是否还有需要通知的IdleHandler的时候有用。如果是初始状态,会获取一次待通知的IdleHandler列表。如果存在需要通知的IdleHandler,会逐一编译进行通知,并且根据keep = idler.queueIdle();的返回值,来决定是否需要移除监听。

背景我们的在业务开发的过程中,可能会遇到这样子的情况,需要再UI线程空闲的时候,做一些操作,那应该怎样子实现呢?MessageQueue.IdleHandlerMessageQueue给我们提供了一个IdleHandler的接口,其定义如下: /** * Callback interface for discovering when a thread is going to...
转载出自:http://bbs.51cto.com/thread-1094228-1.html MessageQueue.IdleHandler可以用来在线程空闲候,指定一个操作;有点类似Handler.postDelayed(Runnable r, long delayMillis),都是在将来的某一个时间 执行一个操作。 不过,使用IdleHandler的好处在于可以不用指定一个将来
IdleHandler是什么? IdleHandler是包含在MessageQueue类中的一个接口,内部只包含一个方法,在消息队列空闲(没有消息或者第一个需要处理的消息在将来执行)回调 publicstaticinterfaceIdleHandler{//当消息队列空闲会被回调,返回值表示是否会被重复执行//返回true,会在mIdleHandlers...
作者:谷言,腾讯移动客户端开发工程师商业转载请联系腾讯WeTest获得授权,非商业转载请注明出处。原文链接:http://wetest.qq.com/lab/view/352.html WeTest 导读 干货!干货!或许可以是一种处理问题的新思路哟! 我们知道android是基于Looper消息循环的系统,我们通过Handle...
# 使用 PeekCompleted 方法查看队首消息但不弹出 queue.Enqueue("第四条消息") next_message = queue.peekCompleted() print("下一条消息是:", next_message) # 输出结果: # 下一条消息是: 第四条消息 希望这个例子可以帮助你理解 MessageQueue 类以及 PeekCompleted 事件的基本用法。如果你有任何问题或需求,请随向我提出。
CSDN-Ada助手: 恭喜您入围 博客专家贡献原力分涨幅「2023-05-16」榜单, 当月原力值增长17分, 原力值涨幅40.0%, 原创博客2篇, 排名第「2」, 一定要再接再厉哦, 争取拿到更好成绩, 榜单详情请看: https://bbs.csdn.net/topics/615327870 更多创作活动请看: 新星计划2023: https://marketing.csdn.net/p/1738cda78d47b2ebb920916aab7c3584?utm_source=csdn_ai_ada_redpacket 新星计划2023: https://marketing.csdn.net/p/1738cda78d47b2ebb920916aab7c3584?utm_source=csdn_ai_ada_redpacket 上传ChatGPT/计算机论文等资源,瓜分¥5000元现金: https://blog.csdn.net/VIP_Assistant/article/details/130196121?utm_source=csdn_ai_ada_redpacket 新人首创任务挑战赛: https://marketing.csdn.net/p/90a06697f3eae83aabea1e150f5be8a5?utm_source=csdn_ai_ada_redpacket Microsoft Edge功能测评!: https://activity.csdn.net/creatActivity?id=10403?utm_source=csdn_ai_ada_redpacket 生物识别技术能否成为应对安全挑战的绝佳选择?: https://activity.csdn.net/creatActivity?id=10411?utm_source=csdn_ai_ada_redpacket 应届生如何提高职场竞争力: https://activity.csdn.net/creatActivity?id=10409?utm_source=csdn_ai_ada_redpacket 讯飞星火大模型将超越chatgpt?: https://activity.csdn.net/creatActivity?id=10407?utm_source=csdn_ai_ada_redpacket 职场新人备忘录: https://activity.csdn.net/creatActivity?id=10405?utm_source=csdn_ai_ada_redpacket VR vs AR:哪种技术更有潜力改变未来?: https://activity.csdn.net/creatActivity?id=10399?utm_source=csdn_ai_ada_redpacket “裸奔”时代下该如何保护网络隐私: https://activity.csdn.net/creatActivity?id=10401?utm_source=csdn_ai_ada_redpacket 蓝桥杯备赛指南分享: https://activity.csdn.net/creatActivity?id=10317?utm_source=csdn_ai_ada_redpacket 有哪些工具软件是一旦用了就离不开的?: https://activity.csdn.net/creatActivity?id=10397?utm_source=csdn_ai_ada_redpacket 量子计算:下一个大风口,还是一个热炒概念?: https://activity.csdn.net/creatActivity?id=10395?utm_source=csdn_ai_ada_redpacket