上篇Android 线程通信 —— Handler 使用说到了 Handler 的使用方法,包括它的 post、send 发送消息的方法,包括它的 Callback、handleMessage 等处理消息的方法。那它是怎么进行消息的管理、怎么把消息通知到对应的线程呢?
上篇说到了组成 Handler 机制的四个主要成员:Handler、Looper、Message、MessageQueue,消息的管理和通知也是主要有它们四个来处理的。
成员 | 备注 |
---|---|
Handler | Handler 在其中主要用于发送和处理 Message |
Message | 整个通信机制中消息的载体 |
MessageQueue | 每个 Looper 会持有一个 MessageQueue,作为消息队列,Handler 发送的消息都会被放到 MessageQueue 中,MessageQueue 中的消息会根据 when 的长短排列 |
Looper | 用于为线程不断从 MessageQueue 中读取 Message 并且交给 Handler 处理,每个线程仅能有一个 Looper,主线程的 looper 在 ActivityThread 的 main() 中被创建,子线程需要我们手动创建 |
我们可以从上篇文章所说到的最后 enqueueMessage 方法看起:
// sendMessageAtTime() 使用的是 enqueueMessage()
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
// mQueue 是 Handler 持有的 mLooper 持有的,在构造方法里做了个引用
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);
}
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
// 可以看到,最后是调用了 MessageQueue 的 enqueueMessage()
return queue.enqueueMessage(msg, uptimeMillis);
}
我们可以 Handler 发送的 Message 都放到了 MessageQueue 中,那 MessageQueue 是如何持有消息的呢?MessageQueue 其实是一个链表结构,持有一个 mMessage 作为头结点,而 Message 有 next 节点,一串的 Message 就组成了 MessageQueue,我们来看看 MessageQueue 是如何存放 Message 的:
boolean enqueueMessage(Message msg, long when) {
...
synchronized (this) {
...
// 将 delay 时间 when 赋值给 msg
msg.markInUse();
msg.when = when;
// 获取当前头结点的 Message
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// 如果没有头结点或者延时为 0,或者延时小于头结点的延时,就将新的 Message 置为头结点
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
// 如果 MessageQueue 中还有消息,或者插入的 Message 的 when 不为 0,就遍历链表,根据 when 的长短,将 Message 插入到对应的位置
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
我们可以看到存放 Message 的逻辑并不是很复杂,就是如果 MessageQueue 中没有消息,就将新消息作为头结点,如果 MessageQueue 中有消息,就根据每个 Message 的 when 由短到长插入。
放完了 Message,那么怎么取呢?这里就要用到 Looper 了。我们知道,在子线程中使用 Handler,我们需要主动创建 Looper 并且调用 Looper.loop(),其实 Looper.loop() 就是在不断的从 MessageQueue 中取出消息并且交给 Handler 的 dispatchMessage() 处理的过程:
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;
...
for (;;) {
// 一直 for 循环,从 MessageQueue 中取 Message
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
try {
// 然后交给 Handler 的 dispatchMessage 处理,在使用 Handler 发送非屏障 Message 时,Handler 会把 this 赋值给 Message 的 target
msg.target.dispatchMessage(msg);
...
} catch (Exception exception) {
...
} finally {
...
}
...
msg.recycleUnchecked();
}
那么 MessageQueue 是怎么通过 next() 来取 Message 的呢?
Message next() {
// 一直 for 循环遍历
for (;;) {
//休眠到下一个 msg 的 when 时间,下面有计算该时间,插入消息也会唤醒
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// msg 的 target 为 Handler,如果为空,则表示这是个同步屏障,则 while 循环找到第一个异步消息
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
// 如果有内存屏障现在的消息为第一个异步消息,否则为第一个消息
if (msg != null) {
if (now < msg.when) {
// 还没到第一个消息的 when,则拿到需要休眠的时间,在上面 for(;;) 开始时,休眠到 msg 准备好
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 正常返回第一个消息,并且将头指针指向下一个消息
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
// 返回消息
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
...
}
}
我们看到是怎么取消息的,也知道取完消息会交给 Handler 的 dispatchMessage() 方法处理,那么 dispatchMessage() 干了什么呢?
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
// msg 有 callback 就直接走 message.callback.run()
handleCallback(msg);
} else {
if (mCallback != null) {
// 如果重写 Handler 的 callback 的 handleMessage 返回 true,就只走 callback 的 handleMessage,否则 Handler 和 callback 的 handleMessage 都会走
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
Handler 的大致通信流程就是这样,但是 Handler 的相关知识并没有结束,比如上面提到的内存屏障、异步消息、Looper 的创建和存取、ThreadLocal等,还有很多需要我们去了解的,争取下一篇放出来。
更新太慢了,太懒了,每天下班11点到家,完全不想看,不想写。。。 努力继续记录吧