了解Handler消息机制前需要先了解Handler在实例化做了什么操作。
实例化
Handler初始化时会获取当前线程的Looper的消息队列()
作为自己的消息队列。也就是说在同一个线程中创建的多个Handler其实用的是同一个消息队列
,也就是当前线程->Looper->消息队列
。
public Handler(Callback callback, boolean async) {
//......
mLooper = Looper.myLooper();
if (mLooper == null) {
//子线程需要手动调用 Looper.prepare() 才会创建该线程的唯一且不可替换的 Looper
//而主线程在启用时就主动进行了初始化,所以不需要手动调用
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
发送消息
向Handler发送消息时,不过是通过什么方式发送,最后都会到达sendMessageAtTime()
方法进行处理。
该方法的作用设置Message
的target
为Handler
本身,然后把Message
入队到上面实例化时提到的消息队列
中。
这里设置的Message.target
就是为了能让指定的Handler
处理消息。
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
处理消息
上面提到,向Handler发送消息其实就是讲详细添加到了Looper
的消息队列里面。那Looper有是如何处理消息的呢?这里先提前说下实现方式,后面再看源码。
-
Looper
执行loop()
方法后会进入一个死循环,作用是从MessageQueue
中获取消息并派发给Message.target
进行处理。直到获取到空消息时才会退出循环。 -
MessageQueue
的next()
方法里面也会进入一个死循环,不断从消息队列中出队消息并返回给Looper
,直到messageQueue.quit()
方法被调用后才会返回空消息,继而让loop()方法
退出循环。 -
messageQueue.next()
在进入循环后会调用nativePollOnce(ptr, nextPollTimeoutMillis)
设置一个有超时时间的阻塞。而在入队方法messageQueue.enqueueMessage()
中会调用nativeWake(mPtr)
取消阻塞。这也是Looper的死循环不会出现问题的原因。
(有兴趣可以自己了解下nativePollOnce
、nativeWake
方法) - 延时执行消息也是通过设置
nativePollOnce()
的超时时间来实现的 - 从代码可以看出,消息队列是用链表来实现的。
以下是Looper和MessageQueue的部分源码
Looper.java
/**
* 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.");
}
final MessageQueue queue = me.mQueue;
//......
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//......
msg.target.dispatchMessage(msg);
//......
}
MessageQueue.java
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;
}
//......
// next()方法里面也用了死循环,这才是Looper没有退出loop的原因
for (;;) {
//......
// 阻塞队列(休眠)用的,防止死循环问题。
// 调用enqueueMessage()方法入队的时候会调用nativeWake(mPtr)唤醒队列
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.
// 如果msg没有target就会被跳过,直到获取到没异步的消息为止
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// 当Message没有到延时执行的时间时,会设置唤醒时间,并在下次循环调用上面的nativePollOnce(ptr, nextPollTimeoutMillis)设置有超时时间的阻塞,然后获取下一个消息。
// 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;
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;
}
// 当Looper调用了quit()方法的时候,会调用MessageQueue的quit()方法,继而设置mQuitting为true,这样next()方法才会返回空,Looper.loop()方法才会跳出循环然后结束掉。
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}