【Android 异步操作】手写 Handler ( 消息队列 MessageQueue | 消息保存到链表 | 从链表中获取消息 )

简介: 【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();
        }
    }





二、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;
        }
    }





三、消息队列完整代码


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



文章知识点与官方知识档案匹配,可进一步学习相关知识

算法技能树leetcode-链表82-删除排序链表中的重复元素 II1793 人正在系统学习中


目录
打赏
0
0
0
0
39
分享
相关文章
Android消息处理机制(Handler+Looper+Message+MessageQueue)
Android消息处理机制(Handler+Looper+Message+MessageQueue)
91 2
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
97 1
Android消息处理机制(Handler+Looper+Message+MessageQueue)
Android消息处理机制(Handler+Looper+Message+MessageQueue)
201 2
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
Android 消息处理机制估计都被写烂了,但是依然还是要写一下,因为Android应用程序是通过消息来驱动的,Android某种意义上也可以说成是一个以消息驱动的系统,UI、事件、生命周期都和消息处理机制息息相关,并且消息处理机制在整个Android知识体系中也是尤其重要,在太多的源码分析的文章讲得比较繁琐,很多人对整个消息处理机制依然是懵懵懂懂,这篇文章通过一些问答的模式结合Android主线程(UI线程)的工作原理来讲解,源码注释很全,还有结合流程图,如果你对Android 消息处理机制还不是很理解,我相信只要你静下心来耐心的看,肯定会有不少的收获的。
340 3
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
Android经典面试题之View的post方法和Handler的post方法有什么区别?
本文对比了Android开发中`View.post`与`Handler.post`的使用。`View.post`将任务加入视图关联的消息队列,在视图布局后执行,适合视图操作。`Handler.post`更通用,可调度至特定Handler的线程,不仅限于视图任务。选择方法取决于具体需求和上下文。
115 0
【Android】Handler 机制 ( Handler | Message | Looper | MessageQueue )(一)
【Android】Handler 机制 ( Handler | Message | Looper | MessageQueue )(一)
195 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等