关于Handler.removemessages方法

作者: 呆呆李宇杰 | 来源:发表于2017-02-16 10:56 被阅读3145次

    在阅读老人的源码中,发现以下代码片段

    private handleMessage(Message msg) {
        switch(msg.what) {
            case ACTION_XXX:
                // do something...
                this.removeMessages(ACTION_XXX);
                break;
    
                //other cases
            }
    } 
    

    1. 猜想

    初步猜测其作用是为了处理某消息后,清除在消息队列中等待的同类消息,以达到防止在处理过程中重复发送的目的

    2. 验证

    于是写一个demo验证之(因为上述源码触发效果过为复杂,所以不用此进行验证)

    mHandler.setHandlerCallBack(new MyHandler.MyHandlerCallBack() {
        @Override
        public void handleMessage(Message message) {
            Log.i(TAG, "handleMessage: " + message.arg1);
            if (message.what == ACTION_ODD) {
                mMyHandler.removeMessages(ACTION_ODD);
            }
        }
    });
    
    mButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Message message = Message.obtain();
            message.what = number % 2 == 0 ? ACTION_EVEN : ACTION_ODD;
            message.arg1 = number;
            
            // 将handleMessage延迟1s调用
            mHandler.sendMessageDelayed(message, 1000);
            number++;
        }
    });
    

    快速点击Button后,观察log日志输出

    02-16 10:51:08.787 17454-17454/com.daijie.handlerapplication I/MainActivity: handleMessage: 0
    02-16 10:51:08.958 17454-17454/com.daijie.handlerapplication I/MainActivity: handleMessage: 1
    02-16 10:51:09.112 17454-17454/com.daijie.handlerapplication I/MainActivity: handleMessage: 2
    02-16 10:51:09.489 17454-17454/com.daijie.handlerapplication I/MainActivity: handleMessage: 4
    02-16 10:51:09.762 17454-17454/com.daijie.handlerapplication I/MainActivity: handleMessage: 6
    02-16 10:51:10.100 17454-17454/com.daijie.handlerapplication I/MainActivity: handleMessage: 8
    02-16 10:51:10.237 17454-17454/com.daijie.handlerapplication I/MainActivity: handleMessage: 9
    

    3. 推论

    从日志输出可以得知偶数全部被输出,而1~9中的奇数被过滤了
    可以推断handleMessage在输出Message.what==1的log结束后,调用Handler.removeMessages将Message.what为ACTION_ODD从消息队列中移除,所以中间的消息被过滤掉了。

    4. 查看源码

    查看源码是最好的验证方式,所以先查看Handler的removeMessages方法源码

    // Handler.java
    public final void removeMessages(int what) {
        mQueue.removeMessages(this, what, null);
    }
    

    可以看出,这里实际上是移除消息队列的message,再看看MessageQueue中的removeMessages方法源码

    // MessageQueue.java
    void removeMessages(Handler h, int what, Object object) {
        if (h == null) {
            return;
        }
    
        synchronized (this) {
             Message p = mMessages;
    
            // 原代码注释,Remove all messages at front.
            // 根据上面传入的参数,p!=null成立,p.target == h成立,object == null 成立
            // 即此处可等同为p.what == what
            // 此处代码即找到第一个p.what == what的消息并将其移除
            while (p != null && p.target == h && p.what == what
                   && (object == null || p.obj == object)) {
                Message n = p.next;
                mMessages = n;
                p.recycleUnchecked();
                p = n;
            }
    
            // Remove all messages after front.
            // 此处即为移除找到第一个后的Message
            while (p != null) {
                Message n = p.next;
                if (n != null) {
                    // 同上,此处也可以等同为p.what == what
                    if (n.target == h && n.what == what
                        && (object == null || n.obj == object)) {
                        Message nn = n.next;
                        n.recycleUnchecked();
                        p.next = nn;
                        continue;
                    }
                }
                p = n;
            }
        }
    }
    

    由源码中可以看出,MessageQueue将Message.what与函数传入的what相同的Message从队列中移除,和推论相符


    这是本人第一次进行探讨,如有什么错误,请在评论区进行纠正。

    相关文章

      网友评论

        本文标题:关于Handler.removemessages方法

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