涉及到的类:
android.os.Looper
消息分发器,负责从MessageQueue中取出Message并交由Handler的dispatchMessage方法处理。android.os.Handler
消息处理器,可以往MessageQueue中插入Message,并处理从MessageQueue中取出的消息。一个Looper可以有多个Handlerandroid.os.MessageQueue
消息队列。一个Thread有一个Looper,一个Looper对应一个MessageQueue。android.os.Message
消息。存储消息类型以及相关信息。
首先看一个四个类的联系图:
消息的五种操作
消息与MessageQueue、Handler、Looper之间的关系如下图:
获取
通过Handler.obtain或者Message.obtain方法获取一个Message变量。
Handler的obtain方法调用的Message的obtain。
message.obtain有多个重载,其无参方法为:
public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message(); }
插入
我们Handler插入消息,插入消息的方法有
sendEmptyMessage(int what)
往消息队列中插入一个仅含有what的消息。
我们可以直接在Android Studio中查看源码实现,代码调用很简单,这里整理了一个表格,上方为7个sendMessage方法,下方从上往下调用序列,空白部分为没调用例如sendMessageAtFrontOfQueue直接调用了enqueueMessage方法。
enqueueMessage方法有三个参数 queue, msg, uptimeMillis,
第一个参数为存储Message的MessageQueue,queue值如下:
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;
我们这里知道mQueue为Looper对应的成员变量MessageQueue,其在Looper.prepare()中初始化,msg即我们要发送的消息,uptimeMills值有4种:
对于sendMessage系列方法,其值为当前时间SystemClock.uptimeMillis();
对于sendMessageDealyed系列方法,其值为当前时间+delayTime;
对于sendMessageAtTime系列为 upTimeMillis,用户直接传的值。
第4种比较特殊,sendMessageAtFrontOfQueue方法为0;这里我们只需知道upTimeMillis的值对应Message的成员变量when。至于when如何应用我们将在下节取回中讲述。
enqueueMessage调用的为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."); } 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; //如果消息队列为空或者调用sendMessageAtFronOfQueue或者当前msg when小于头消息的when,则将当前消息插入到队头 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大于要插入消息的when。 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; }
取出
Looper.loop方法为循环从MessageQueue中取出消息,
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; // 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 (;;) { //真正的取消息方法 Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } // This must be in a local variable, in case a UI event sets the logger final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } final long traceTag = me.mTraceTag; if (traceTag != 0) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } try { //分发消息 msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } // Make sure that during the course of dispatching the // identity of the thread wasn't corrupted. final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); } //消息回收 msg.recycleUnchecked(); } }
然后我们看下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());
}
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.
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;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// 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;
}
}
下面用一张图说明取出消息的逻辑:
首先在消息队列中的顺序为t1 < t2 < t3(message的when值),消息被分发满足的条件必须为msg.when < now(当前时间),如果消息when大于当前时间,就会保持等待,直到消息的when变量小于当前时间,在此期间我们可以往消息队列中发送任意消息,例如我们发送一个t4,如果t2.when < t4.when < t3.when那么此时消息队列顺序为 t1 < t2 < t4 < t3,从这里我们可以看到sendMessageAtFrontOfQueue怎么实现的,其when赋值为0,因此我们在该方法中发送一个消息t0,t0的when小于消息队列中所有的msg.when。所以t0会被第一个取出并分发。
分发处理
分发处理为Looper.loop方法中的msg.target.dispatchMessage();
msg.target为Handler类型变量,那么target什么时候赋值呢,其在Message
public static Message obtain(Handler h) { Message m = obtain(); m.target = h; return m; }
直接将Handler赋值给taget,但是我们知道一般情况下我们直接用message.obtain()方法获取一个message。这里并没有对target初始化,那么target变量在哪里赋值的呢,我们在分析插入消息的时候发现sendMessage方法系列最后都会走Handler.enqueueMessage方法,看下enqueueMessage方法源码。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { //这里这里!!! msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
这里我们看到了注释部分,即sendMessage的时候会指定message的target。我们现在知道了即由发送消息的Handler处理该消息,然后我们看下dispatchMessage方法
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
即分发消息首先分发给message.callback,如果message.callback为null,再分发给handler.callback,handler.callback为null,再分发给handler.handleMessgae()方法。
移除
通过handler可以移除消息:
Handler的remove方法如下:
removeCallbacks(Runnable r)
removeCallbacks(Runnable r, Object token)
removeMessages(int what)
removeMessages(int what, Object object)
removeCallbacksAndMessages(Object token)
通过源码发现其最终调用为MessageQueue的removeMessage系列方法,我们看下removeMessages源码:
void removeMessages(Handler h, Runnable r, Object object) { if (h == null || r == null) { return; } synchronized (this) { Message p = mMessages; // Remove all messages at front. while (p != null && p.target == h && p.callback == r && (object == null || p.obj == object)) { Message n = p.next; mMessages = n; p.recycleUnchecked(); p = n; } // Remove all messages after front. while (p != null) { Message n = p.next; if (n != null) { if (n.target == h && n.callback == r && (object == null || n.obj == object)) { Message nn = n.next; n.recycleUnchecked(); p.next = nn; continue; } } p = n; } } }
其从MessageQueue队列中找到和传递参数对应的Message然后移除,及recycled(将Message的变量设置为初始值)。具体可参见Message的recycleUnchecked()代码,这里不再贴出。
上面我们讲了message的五个操作,获取、插入、取出、分发,移除。
从这三个操作中我们可以看到消息的几种状态
当通过obtain方法获取一个Message时,如果没有消息池中没有可以复用的message,则create一个新消息,消息状态为initialized,然后通过Handler插入到MessageQueue,此时消息已经有了what,when等信息,如果msg.when>now,消息会进入pending状态,直到msg.when<=now,此时消息处于dispatched状态,然后被回收,进入到recycled状态并被保存到消息池,方便我们下次直接使用消息。
我们看下Message类的变量
这里我们关注下callback,在分发中我们知道message.callback是最高优先级处理消息的,其通过handler的post方法设置,handler的post方法有下面几个
boolean post(Runnable r)
boolean postAtFrontOfQueue(Runnable r)
boolean postAtTime(Runnable r, Object token, long uptimeMillis) boolean postAtTime(Runnable r, long uptimeMillis)
boolean postDelayed(Runnable r, long delayMillis)
通过查看源码发现其实post方法都是调用相应的sendMessage方法,只不过message是通过getPostMessage方法获得,
private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; } getPostMessage设置了message的callback。
IdleHandler
MessageQueue有一个IdleHandler,其定义如下:
public static interface IdleHandler { boolean queueIdle(); }
这个是做什么用的呢,假设现在MessageQueue中有3个Message t0,t1,t2;
并且t0.when < now < t1.when < t2.when,当t0被分发处理之后,由于now < t1.when,此时线程会进入等待状态,直到now >= t1.when,在t1.when - now这段时间内,我们可以通过IdleHandler做一些事情,实现代码如下:
class IdleHandler implements MessageQueue.IdleHandler{
@Override
public boolean queueIdle() {
//执行一些代码,例如打印log说明此时在等待
return false;
}
}
handler.getLooper().myQueue().addIdleHandler(new IdleHandler());
另外我们可以通过
handler.dump(new LogPrinter(Log.DEBUG,TAG),""); handler.getLooper().setMessageLogging(new LogPrinter(Log.DEBUG,TAG));
来打印当前handler所在的MessageQueue分发message的一些log信息,通过这个,我们可以监听当前thread的阻塞运行等状态,具体可参见这篇文章:
Android卡慢监控组件简介