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()
呢?这个时候我们不妨打开 Looper
的 prepare()
方法,源码如下 ——
prepare()
根据源码我们可以看到,先从 ThreadLocal
中 get()
一下,如果当前 get()
的值为 null,那么我们就给 ThreadLocal
对象 set
一个 new Looper()
对象,我们再定位到 Looper
的构造方法看一下 ——