类似Binder机制,MessageQueue、Looper也有底层的C++实现,涉及文件管道和驱动等。 以下仅从Java层的Looper、Handler和MessageQueue等相关类型的源码来分析线程消息处理的机制。
Looper用来创建和启动消息队列。 Looper对象和线程绑定是通过ThreadLocal实现的。 它提供了各种getter方便获取线程关联的MessageQueue和Looper对象。
Looper.prepare();
Looper.prepareMainLooper();
线程通过执行Looper.prepare()来创建关联的MessageQueue。
主线程则调用prepareMainLooper()来创建主线程关联的Looper,方便其它线程向主线程发消息。
它新建了Looper对象,以ThreadLocal存储它,所以和当前线程绑定。
构造函数中创建了消息队列:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
// MessageQueue.java
private long mPtr;
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
nativeInit()调用C++代码创建底层的C++MessageQueue对象。 有了MessageQueue对象以后,接着需要开启消息循环,使用关联的Handler来发送、处理消息了。
MessageQueue有点像一个阻塞队列,它提供MessageQueue.next()用来从队列中取出一个Message对象。 若没有消息则调用会阻塞。
Looper.loop()用来开启对MessageQueue的取消息操作的无限循环。
public static void loop() {
final Looper me = myLooper();
...
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);
...
msg.recycleUnchecked();
}
}
可以看到,loop()的操作就是无限从queue中调用next()获取一个新Message对象,然后执行dispatchMessage来处理它。
nativePollOnce()用来检查队列中是否有新的消息。
参数nextPollTimeoutMillis表示在暂无消息时此次检查过程需要休眠的时间:
使用for (;;) 无限循环检查是否有消息,直到返回一个Message对象。 若当前MessageQueue正在退出,则返回null作为标识。
Message next() {
...
int nextPollTimeoutMillis = 0;
for (;;) {
...
nativePollOnce(ptr, nextPollTimeoutMillis);
...
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message msg = mMessages;
...
if (msg != null) {
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.
...
mMessages = msg.next;
msg.next = null;
...
return msg;
}
} else {
// 继续循环等待消息
nextPollTimeoutMillis = -1;
}
...
// 每次执行next()时,若当前没有消息可处理,那么就找到所有的idle handlers,回调它们
...
}
// 回调idle handlers. 每次调用next()只会执行一次
...
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
每次调用next()时,第一次检查如果发现没有要出来的消息,就一次性调用所有在注册了的IdleHandler回调对象。
MessageQueue和Looper对象都是和某个线程关联的。 向一个线程发送消息,通过和它绑定的一个Handler对象进行。 执行创建Handler对象的的线程,Handler对象和此线程绑定。
Handler对象的构造函数中,将当前线程关联的Looper和MessageQueue保存到其字段中。
public Handler(Callback callback, boolean async) {
...
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
每个发送到线程关联的MessageQueue中的Message对象,主要字段有:
发送消息的一般形式为:
boolean sendMessageAtTime(Message msg, long uptimeMillis);
boolean sendMessageDelayed(Message msg, long delayMillis);
boolean sendEmptyMessageAtTime(int what, long uptimeMillis);
boolean sendEmptyMessageDelayed(int what, long delayMillis);
若不指定when那么它为当前时间,之后被Looper取出后立即执行;
sendMessage()中将Handler Message.target
设置为自身,最执行Handler绑定的队列的MessageQueue.enqueue()方法。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
字段Message Message.next
用来指向Message链表中的下一个对象。
MessageQueue.mMessages字段指向了它拥有的消息链表的头结点。
mMessages中的消息根据其when的时间排列,时间近的在前面。
enqueueMessage()在添加消息时将它放到mMessages的合适的位置。
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.");
}
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;
}
mBlocked记录当前队列是否处于休眠? 在next()时若最近要处理的消息的when还未到或队列空时,则在检查队列是否空时会主动休眠一段时间。
若新的Message被添加到链表头,且它的when时间到了,那么就唤醒Looper继续执行next(),获取此Message然后处理它。
if (needWake) {
nativeWake(mPtr);
}
在Looper.loop()中,每当获取新的消息后:
Message msg = queue.next(); // might block
...
msg.target.dispatchMessage(msg);
target就是发送Message的Hander。 Hander发送消息到其绑定的MessageQueue中。 可见,相关的Looper、MessageQueue、Handler都是和同一个线程关联的。
从next()的执行在Looper.loop()的循环中进行可知: Hander.dispatchMessage()的调用就是在Looper关联的线程中进行。
public class Handler {
final Callback mCallback;
/**
* Callback interface you can use when instantiating a Handler to avoid
* having to implement your own subclass of Handler.
*
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
public interface Callback {
public boolean handleMessage(Message msg);
}
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
}
上面的Message.callback是一个Runnable。 Handler.mCallback是创建它时指定的一个回调对象。 handleMessage()就是子类重写处理自定义消息的地方。
Looper.loop()执行后,线程“阻塞”,不断从关联的MessageQueue中取出消息并处理。 其它线程或在处理某个消息的逻辑中,可以调用Looper.quit()退出当前线程的消息循环。
// Looper.java
final MessageQueue mQueue;
...
public void quit() {
mQueue.quit(false);
}
它执行了MessageQueue.quit()。
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
这里设置mQuitting为true。 之后下次调用next()时,返回null告知Looper.loop()退出循环。 线程的消息循环结束。