1.前提
前面说到sendMessage携带的delay会被加上SystemClock.uptimeMillis() ,最终赋值给Message的when。
msg.when = SystemClock.uptimeMillis() + delayMillis;
那么when除了用来在链表里面作为排序依据以外,还在哪里用到了呢?
2.Looper.loop
首先看下Looper的loop里面,循环取queue的msg,如果msg为null,返回;否则执行msg
public final class Looper {
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); //执行Message
msg.recycleUnchecked(); //msg放入缓存
}
}
}
3.MessageQueue.next
看下queue.next()的实现,会通过when计算下一条消息需要等待的时长。
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
public final class MessageQueue {
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();
}
//等待nextPollTimeoutMillis,不往下执行
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) {
if (now < msg.when) { //当前时间小于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;//将msg从链表中移除
} else {
mMessages = msg.next; //更新表头
}
msg.next = null;
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
}
// 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;
}
}
}