发送一条延迟消息比如handler.sendMessageDelayed的流程:
1、
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
2、
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);
}
3、
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;//将handler赋值给msg
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
前面的这三步比较好理解
1、发送一个延迟消息,延迟时间和当前时间相加计算出消息发送时间
2、获取当前消息队列,根据消息发送时间进行排序
3、调用消息队列中的排序方法进行排序
4、我们看一下具体的排序:
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;//将当前消息赋值给p(当前时间是一个全局变量)
boolean needWake;
if (p == null || when == 0 || when < p.when) {
//如果当前消息为空,或新插入消息的发送时间==0或新插入的消息的发送时间小于当前时 间的发送时间。就将当前消息传入新插入消息的next,再将新插入消息赋值给当前消息(即将新插入消息排到当前消息前面)
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
//如果不符合条件遍历消息队列,根据when将插入消息插入到应有的位置
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;
}
//如果需要唤醒就唤醒
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
以上四步是将消息按照发送时间进行排序,下面介绍如何进行消息的延迟发送:
首先在ActivityThread中的main方法里调用Looper.loop()可以看到里面启动了一个死循环调用消息队列的next()方法去查消息队列中的消息,
Message next() {
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) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
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 {
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
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);
}
}
}
pendingIdleHandlerCount = 0;
nextPollTimeoutMillis = 0;
}
}
可以看到,在这个方法内,有一个for循环里面有
nativePollOnce(ptr, nextPollTimeoutMillis);
nextPollTimeoutMillis是阻塞时间,为-1时候,一直阻塞,直到被唤醒,为0不需要阻塞,大于0为阻塞的时间,时间到了,唤醒线程。
当一个新的消息发送进来而之前的消息还没有到发送时间这说明此时的线程是阻塞状态的,如果新的消息发送时间比原有消息早(如第4步),这时候就会先进行排序将新消息排在原有消息前,然后调用nativeWake唤醒线程,去处理新加入的消息。如果新加入的消息发送时间没到,或者处理完新消息后原有消息发送时间还没到,线程将再次进入阻塞状态,等待发送时间到达或者再次nativeWake唤醒线程