#再论Handler—Handler原理解析
标签(空格分隔): Android架构师之路
Handler,无论你菜鸟还是像我一样的老菜鸟,都无法避免这个亘古不灭的话题,只有了解学会Handler的原理,你才能变成一个出的厅堂下得厨房的优秀的老菜鸟。其实同类优秀的帖子已经很多了,但是为了强化记忆我的理解,还是想再次记一下,我心中的Handler。
要介绍Handler,就必须要介绍与它息息相关甚至“同为一体”的其它几个类:Looper、MessageQueue、Message。所以本篇文章就分为三个部分:
- Handler、Looper、MessageQueue、Message原理及关系。
- Handler事件分发原理。
- Handler线程切换原理。
1. Handler、Looper、MessageQueue、Message原理及关系。
1.1 Message
Message是定义一个包含描述和可以发送到Handler的任意数据对象的消息。
我们先看Message的几个关键变量:

target,就是负责发送且分发它的Handler;
callback,是一个Runnable回调;
next,下一个消息池中的它之下的message。
现在有3个问题:
- 1.target从哪来来,作用是什么?
- 2.callback又是什么及其作用;
- 3.还有next是什么?
我们先不着急给出答案,接着往下看。
1.2 MessageQueue 消息队列
它持有并维护了当前线程的Looper分发的消息列表。消息并不是直接而是通过Handler 关联的Looper入队列的。
MessageQueue看上去是消息队列,然而它实际上只是消息队列的管理者。消息列表是它持有的Message mMessage,是由Message组成的单链表结构。
我们看它管理消息的两个核心方法:
- boolean enqueueMessage(Message msg, long when) ;
- Message next()。
1.2.1 boolean enqueueMessage(Message msg, long when) ,消息入队列;
先上代码:
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
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;
}
可以看到,在第一行就校验了msg.target是否为null,由此可知,msg必须关联(持有)负责分发它的handler;
最重要的是for循环里入队的这部分,通过逐个和消息列表里消息的发生时间对比,找到与当前入队的message的 -分发时间-之前与它时间最接近的preMsg,将mesage设置到preMsg的next(此处也解答了问题3:message的next是什么),最终得到的是一个按时间先后顺序排列的链表;
此外,入队操作还做了一件事情:当消息入队时候,如果队列为空的或需要立即分发或当前消息分发时间-早于消息队列中最近一个需要分发的消息的时间的(而此时MessageQueue的next()方法的循环是处于阻塞状态的),就调用一个native方法nativeWake()唤醒取出消息的next()(next方法的循环会被nativePollOnce()native方法阻塞)循环。
1.2.2 Message next();
先上源码
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//-1-直接休眠一定的时间;
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;
//-2-找出下一个需要分发的消息。
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
//-3- 如果时机未到,即当前时间还不到消息的处理时间,就计算休眠时间,
//反之,返回这个待处理的消息。并将休眠状态mBlocked置为false
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
// 还没有到下一个消息触发时间,那么在它之前休眠(休眠一段时间)
nextPollTi

本文深入探讨Android中的Handler机制,解析Handler、Looper、MessageQueue和Message的原理与关系,阐述Handler事件分发和线程切换机制,揭示线程切换的本质。
最低0.47元/天 解锁文章
9447





