从源码角度分析 Handler、Looper、Message、MessageQuene

Android 的线程间通信主要是通过 Handler 来实现,那么具体是怎么实现运转的呢?下面就从源码的角度进行分析。

首先从英文字面上这几个单词可以理解为 Handler(执行者),Looper(循环者),Message(消息),MessageQuene(消息队列)。

Looper

我们在子线程使用 Handler 的时候一定要调用 Looper 的以下两个函数(主线程默认已经调用了这两个函数):

1
2
looper.prepare()
looper.loop()
looper.prepare()
1
2
3
4
5
6
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}

在 prepare() 方法中,我们看到了一个全局变量 ThreadLocal。ThreadLocal 是一个线程内部的数据存储类,在 Handler 的运行机制中具有很重要的作用,它可以在指定的线程中存储数据,数据存储后,只有在指定线程中可以获取到存储的数据,对于其他线程来说无法获取到数据。对于 Handler 来说,它需要获取当前线程的 Looper,这个时候通过 ThreadLocal 就能轻松实现 Looper 在当前线程中的获取。

在 prepare() 函数中,当前线程下 ThreadLocal 如果取不到 Looper 对象,便会在 ThreadLocal 中创建一个当前线程下的 Looper。继续看 Looper 的构造函数

1
2
3
4
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}

可以发现 Looper 内维护了一个消息队列和一个线程。

looper.loop()
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
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}

在 loop() 方法中可以看到又一个 for 循环,循环每次都从 MessageQuene 中取出 Message,当取出的 Message 为空的时候就直接 return 掉,否则执行 msg.target.dispatchMessage(msg)(分发该消息,msg.target 是什么待会再说)。

Handler

Handler 在发送消息的时候有许多种方法,大多都是要通过 sendMessageAtTime() 发送。

1
2
3
4
5
6
7
8
9
10
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}

enqueueMessage() 方法代码如下:

1
2
3
4
5
6
7
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}

可以看到 Message 正是在这个方法内被 Handler 装进了 MessageQuene。更让人激动的是我们发现了 msg.target = this 这行代码,这也就意味着在 Looper 的 loop() 方法中,msg.target.dispatchMessage(msg) 表示执行消息分发的是 Handler。我们再去 Handler 中搜索 dispatchMessage() 方法。

1
2
3
4
5
6
7
8
9
10
11
12
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}

发现了我们熟悉的 handleMessage(msg) 方法,原来回调都是在这里。

至此,整个流程大致如下:

Handler 执行发送消息的相关方法后,Message 被装进 MessageQuene 中。线程中的 Looper 则是在 loop() 方法内不断尝试从 MessageQuene 内取出 Message,然后调用与该 Message 绑定的 Handler(msg.target)对象的 dispatchMessage() 方法。最后可以看到处理消息的 handleMessage() 方法就是在 dispatchMessage() 方法内被调用的。

总结

  1. 在线程间通信中,子线程通过调用主线程的 Handler 的发送消息函数把子线程的 Message 发送到 MessageQuene 中。由于主线程默认调用了 Looper.loop() 方法,他会不断地去查询主线程的 MessageQuene 中是否有 Message 对象,如果有的话就把对象取出给主线程的 Handler 进行处理,从而达到了线程间通信。
  1. 一个线程可以有多个 Handler,但是一个线程只能对应一个 Looper 和一个 MessageQuene。