- Handler post方法
public final boolean post(Runnable r, long delayMillis) {
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
post -> sendMEssageDelay(msg,long delay) -> sendMessageAtTime
-
postDelay public final boolean postDelayed(Runnable r, long delayMillis) {
return sendMessageDelayed(getPostMessage(r), delayMillis);}
显然,当前的postDelay和post的方法是来自于当前的一个处理方式
.点进sendMessageAtTime()方法看看
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);} 追到这里依然没有看到,他在存放的时候有什么不同,但是显然证实了消息不是延迟放进MessageQueen的,那是肿么处理的,是在轮训的时候处理的吗?,
4.我们点进Looper中看一下,主要代码,Looper中的looper调用了MessageQueen中的next方法,难道是在next()方法中处理的? public static void loop() {
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
···
我们点进MessageQueen中的next()方法
for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); }
nativePollOnce(ptr, nextPollTimeoutMillis);
···
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;
}
···
}
}
很贴心的给出了注释解释“ Next message is not ready. Set a timeout to wake up when it is ready.”,翻译“下一条消息尚未准备好。设置一个超时,以便在准备就绪时唤醒。”
when就是uptimeMillis, for (;;) 相当于while(true),如果头部的这个Message是有延迟而且延迟时间没到的(now < msg.when),不返回message 而且会计算一下时间(保存为变量nextPollTimeoutMillis),然后再循环的时候判断如果这个Message有延迟,就调用nativePollOnce(ptr, nextPollTimeoutMillis)进行阻塞。nativePollOnce()的作用类似与object.wait()。得出结论是通过阻塞实现的。
6.但是如果在阻塞这段时间里有无延迟message又加入MessageQueen中又是怎么实现立即处理这个message的呢?,我们看MessageQueen中放入消息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;
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;
}
在这里p 是现在消息队列中的头部消息,我们看到| when < p.when 的时候它交换了放入message与原来消息队列头部P的位置,并且 needWake = mBlocked; (在next()中当消息为延迟消息的时候mBlocked=true),继续向下看 当needWake =true的时候nativeWake(mPtr)(唤起线程)
一切都解释的通了,如果当前插入的消息不是延迟message,或比当前的延迟短,这个消息就会插入头部并且唤起线程来
handler.postDelay() 的实现 是通过MessageQueue中执行时间顺序排列,消息队列阻塞,和唤醒的方式结合实现的。
如果真的是通过延迟将消息放入到MessageQueen中,那放入多个延迟消息就要维护多个定时器