从源码角度简析 Android 消息机制

本文从源码角度详细分析了Android消息机制中的MessageQueue、Looper和Handler。首先,介绍了MessageQueue的enqueueMessage()和next()方法,揭示了其内部单链表的数据结构。接着,探讨了Looper的prepare()、loop()和quit()方法,解释了消息循环的工作原理。最后,分析了Handler的构造方法、send()和post()系列方法以及dispatchMessage(),梳理了消息的发送与处理流程。文章还给出了Handler的最佳实践,强调了静态内部类的使用以避免内存泄漏,并补充了关于主线程Looper和MessageQueue的知识点。
摘要由CSDN通过智能技术生成

MessageQueue 源码解析

`MessageQueue` 直译过来就是消息队列的意思,但是实际上 `MessageQueue` 的底层实现不是 java 中的不是用的队列,而是使用一个单链表,多说无益,我们从代码的角度来一探究竟。打开 `MessageQueue` 源码,首先是类的介绍 ——

这里写图片描述

直译过来大概就是:

一个持有通过 Looper 来发送消息队列的低级类,Message 对象不会立即添加进 MessageQueue,而是通过与 Looper 关联的 Handler 对象来添加。
你可以通过 Looper 的 myQueue() 方法找到当前线程的 MessageQueue 对象

这里先暂时放在这,我们再来看一看 MessageQueue 的进出队列方法,毕竟 MessageQueue 在消息机制中扮演消息队列的角色,其最重要的方法当然就是进出队列方法了,首先看进入队列的方法 ——

enqueueMessage()

这里写图片描述

关键点在第565~576行代码间,我们可以看到我们将新传进来的 Message 对象是根据 when 来放入的,最终这个 Message 对象所处的位置的前一个 Message 对象的 when 值比它小,同时我们也可以看到,对于一个 Message 对象来说,它内部是使用 next 变量持有下一个 Message 对象的引用,这里我们可以打开 Message 的源码查看到,源码如下:

这里写图片描述

所以我们前面所提到的 MessageQueue 对象底层实现其实就是一个单链表原因就在此。

解决完入队方法,我们再来看看出队方法,MessageQueue 中的出队方法源码如下:

next()

这里写图片描述

我们看到318行代码处,for 循环是一个死循环,如果消息队列中没有消息,那么循环将会一直阻塞在这里,而如果有消息的话,如代码344~352行代码处所示,该消息对象将会被移出单链表并且被返回。

到此 MessageQueue 源码解析就暂时告一段落了,接下来看一下 Looper 源码的解析。

Looper 源码解析

打开 Looper 类源码,类的注释如下图——

这里写图片描述

直译如下:

一个使线程内消息循环的类,默认情况下线程并没有启动小心循环;创建了一个新的 Looper 对象,需要调用它的 prepare() 方法来开始使得消息循环,然后 loop() 方法就会一直处理消息,直到循环停止。

大部分的消息循环交互是通过 Handler 类实现的。

这里有一个经典的实现 Looper 的线程的例子,使用 prepare() 和 loop() 两个方法让 Looper 能够和普通的 Handler 交互。

class LooperThread extends Thread {
    public Handler mHandler;

    public void run() {
        Looper.prepare();

        mHandler = new Handler() {
            public void handleMessage(Message msg) {
                // process incoming messages here
            }
        };

        Looper.loop();
    }
}

简单来说,需要通过 Looper.prepare() 方法才能给当前线程创建 Looper 对象,并且需要调用 Looper.loop() 方法才能让当前线程的 MessageQueue 中的消息循环被处理。这里可能有小伙伴有疑惑,为什么需要使用 Looper.prepare() 来创建一个 Looper 而不是 new Looper() 呢?这个时候我们不妨打开 Looperprepare() 方法,源码如下 ——

prepare()

这里写图片描述

根据源码我们可以看到,先从 ThreadLocalget() 一下,如果当前 get() 的值为 null,那么我们就给 ThreadLocal 对象 set 一个 new Looper() 对象,我们再定位到 Looper 的构造方法看一下 ——

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值