Handler消息机制,主要由4个类构成
1.Handler 发送和处理消息
2.Message 消息的载体
3.MessageQueue 存储消息的队列,实际他更像是单链表
4.Looper 消息循环,主要是取出MessageQueue中的Message进行分发
几者之间的关系如图
下文就按照执行的流程,分析一下执行过程中具体的步骤和执行的操作
1.Looper
可以先看一下Looper的构造器
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
可以看到Looper的构造器内部会自动创建MessageQueue对象,所以可以说Looper
和MessageQueue是绑定创建的。
在子线程创建Looper一般不是直接通过构造器,而是调用静态方法Looper.prepare(),
一起看下
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));
}
可以看到,新建的Looper保存到了sThreadLocal中,这个是一个ThreadLocal对象可以
在不同线程中保存同一变量的不同副本,使线程之间相同变量保持独立。
2.Handler
先来看下他的构造器
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
//调用静态方法,取出当前线程的Looper对象,其实就是取出ThreadLocal
//中保存的之前创建的Looper
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
//取出looper中创建的MessageQueue,这个Handler发送的Message都会添加
//到这个MessageQueue中,由于同一个线程取出的MessageQueue是相同的
//所以同一个线程的多个Handler对应同一个MessageQueue,即Handler与
//MessageQueue可以为 多对一关系
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
再看一下Handler的一个功能,发送消息。发送消息可以调用sendXXX或者post,最终来到sendMessageDelayed()
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
又转到sendMessageAtTime
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入队。
入队后就是MessageQueue的入队操作,接下来就与MessageQueue相关了
3.MessageQueue
接着上面的操作,看下enqueueMessage过程
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
//上面检测Message的合法性
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;
//这玩意相当这个链表的头结点(MessageQueue的操作实际是一个单链
//表操作)
Message p = mMessages;
boolean needWake;
//如果头结点为null或者添加的Message的时间小于头结点,将新加的作为头
//节点,这里就是一个链表的添加操作
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;
//如果不符合条件,就继续遍历,看新加的Message的时间when
//在哪两个Message之间,然后做插入操作
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
//两个结点之间插入这个Message
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;
}
看了添加,我们看下怎么取出,取出用到了MessageQueue的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();
}
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) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
//找到第一个非同步屏蔽的Message
if (msg != null) {
//还没到message该处理的时间
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
//到处理时间了
// Got a message.
mBlocked = false;
//取出目标节点,重新设置结点的next引用
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;
}
//省略部分代码
}
}
可以看到还是单链表的删除操作,如果找不到目标Message,这里会一直循环,阻塞在这个地方
当然,next方法不会自己启动,调用它的就是Looper,在Looper的loop方法中调用了它
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//取出Looper中的MessageQueue对象
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 (;;) {
//在这里调用MessageQueue的next方法,取出下一个Message
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//省略部分代码
try {
//msg.target就是发送这个Message的Handler,调用它的
//dispatchMessage()来处理消息,因为这个方法在这里
//被调用,所以handler处理消息的过程就会跑到当
//前的线程中,也就是Looper的创建线程
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
//省略部分代码
msg.recycleUnchecked();
}
}
由于loop方法在执行死循环,所以如果在子线程创建了消息队列,不再使用时最好调用
Looper的quit()直接退出循环,或者quitSafely等待消息处理完退出。