当前位置:   article > 正文

【Android 异步操作】手写 Handler ( 消息队列 MessageQueue | 消息保存到链表 | 从链表中获取消息 )_messagequeue 是存储在哪里的?

messagequeue 是存储在哪里的?





一、MessageQueue 消息队列存储消息



Message 链表 : 消息队列 MessageQueue , 内部维护了一个 Message 链表 , 存储的时候只存储第一个 Message 即可 ;

链表插入元素 :Handler 在其它线程调用 sendMessage 方法 , 将 消息 Message 放入 Looper 中的 MessageQueue 时 , 针对该链表的操作就是 , 循环获取链表的下一个元素 , 最终 获取到最后一个元素 , 最后一个元素的 next 为空 ; 将 最后一个元素的 next 设置为本次要插入的 Message , 即可完成消息存储到消息队列的操作 ;

链表元素同步 : 链表为空时 , 取出链表的操作会阻塞 , 调用的是 wait 方法 , 此时有消息加入链表后 , 需要 调用 notify 唤醒阻塞 ;

消息入队的部分代码 :

    /**
     * 该队列是一个链表 , 因此这里只给出第一个 Message 即可
     */
    Message mMessage;

    /**
     * 将 Message 消息加入到 Message 链表中
     * @param msg
     */
    public void enqueueMessage( Message msg ){
        // 因为 该消息队列 可能会有多个线程 通过 Handler 向消息队列中添加消息
        // 因此 需要使用同步代码块包裹以下逻辑
        synchronized (this){
            if( mMessage == null ){
                mMessage = msg;
            }else{
                /*
                    如果链表不为空
                    这里需要循环查找消息队列的最后一个消息
                    将本次传入的 Message msg 参数加入到链表尾部
                 */
                Message pointer = mMessage;
                Message previous = pointer;
                for(;;){
                    // 记录上一条消息, 每次遍历都将本次遍历的记录下来
                    previous = pointer;

                    // 将 pointer 指向下一条消息
                    pointer = pointer.next;

                    // 此时如果某个 Message 的 下一个元素为空
                    // 说明该 Message 是消息队列最后一个元素
                    if(pointer == null){
                        break;
                    }
                }
                // 将本次参数传入的 Message 放到链表最后
                previous.next = msg;
            }
            notify();
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42




二、MessageQueue 消息队列取出消息



Looper 调用 loop 方法后 , 会一直循环 , 不断地从 消息队列 MessageQueue 中取出 Message 消息 , 然后 将 Message 消息发送给对应的 Handler 执行对应的操作 ;

从 消息队列 MessageQueue 中取出消息 , 也是 取出链表表头 的操作 , 取出该链表的表头 , 然后 将表头设置成链表的第二个元素 ;

消息同步 : 如果当前链表为空 , 此时会 调用 wait 方法阻塞 , 直到消息入队时 , 链表中有了元素 , 会调用 notify 解除该阻塞 ;

    /**
     * 从消息队列中获取消息
     * @return
     */
    public Message next(){
        synchronized (this){
            // 本次要获取的消息, 最后要返回到 Looper 中 loop 方法中
            Message result;

            for (;;){
                // 尝试和获取 消息队列 链表中的第一个元素
                result = mMessage;
                if(result == null){
                    // 如果当前的 Message 队列为空 , 阻塞等待 , 直到新的消息到来
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else{
                    // 如果不为空 , 说明已经获取到最终的消息 , 退出循环即可
                    break;
                }
            }

            // 处理链表逻辑 , 将表头指向下一个 Message
            mMessage = mMessage.next;

            return result;
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31




三、消息队列完整代码



package kim.hsl.handler;

public class MessageQueue {

    /**
     * 该队列是一个链表 , 因此这里只给出第一个 Message 即可
     */
    Message mMessage;

    /**
     * 将 Message 消息加入到 Message 链表中
     * @param msg
     */
    public void enqueueMessage( Message msg ){
        // 因为 该消息队列 可能会有多个线程 通过 Handler 向消息队列中添加消息
        // 因此 需要使用同步代码块包裹以下逻辑
        synchronized (this){
            if( mMessage == null ){
                mMessage = msg;
            }else{
                /*
                    如果链表不为空
                    这里需要循环查找消息队列的最后一个消息
                    将本次传入的 Message msg 参数加入到链表尾部
                 */
                Message pointer = mMessage;
                Message previous = pointer;
                for(;;){
                    // 记录上一条消息, 每次遍历都将本次遍历的记录下来
                    previous = pointer;

                    // 将 pointer 指向下一条消息
                    pointer = pointer.next;

                    // 此时如果某个 Message 的 下一个元素为空
                    // 说明该 Message 是消息队列最后一个元素
                    if(pointer == null){
                        break;
                    }
                }
                // 将本次参数传入的 Message 放到链表最后
                previous.next = msg;
            }
            notify();
        }
    }

    /**
     * 从消息队列中获取消息
     * @return
     */
    public Message next(){
        synchronized (this){
            // 本次要获取的消息, 最后要返回到 Looper 中 loop 方法中
            Message result;

            for (;;){
                // 尝试和获取 消息队列 链表中的第一个元素
                result = mMessage;
                if(result == null){
                    // 如果当前的 Message 队列为空 , 阻塞等待 , 直到新的消息到来
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else{
                    // 如果不为空 , 说明已经获取到最终的消息 , 退出循环即可
                    break;
                }
            }

            // 处理链表逻辑 , 将表头指向下一个 Message
            mMessage = mMessage.next;

            return result;
        }
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/寸_铁/article/detail/956944
推荐阅读
  

闽ICP备14008679号