Handler進階之sendMessage
?本文主要進一步的探索Handler,主要介紹下Handler是如何發送消息的?
?用過Handler的想必對一下幾個方法都不會陌生:
sendMessage(Message msg);//立刻發送消息
sendMessageAtTime(Message msg, long atTime);//在某個時間點發送消息
sendMessageDelayed(Message msg, long delayedTime);//在當前時間點延遲一段時間發送消息
?以上是三個Handler發送消息的方法,區別在于發送的時間點不一致,但其實三個方法在最終都是執行Handler內的同一個方法,只是在參數上稍有區別:
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
sendMessage(Message msg);
//對應
sendMessageDelayed(msg, 0);
sendMessageAtTime(Message msg, long atTime);
//對應
sendMessageDelayed(msg, atTime)
sendMessageDelayed(Message msg, long delayedTime);
//對應
sendMessageDelayed(msg, SystemClock.uptimeMillis() + delayedTime)
?從上面的代碼能夠看出,最終的消息發送都是傳入了要發送Message對象和對應需要發送Message的時間點。
我們猜想,Handler發送消息難道是根據Message需要發送的時間點設置一個定時器讓Message在某個時間點被發送出去?
如果僅此而已的話,你也太小看google的大牛們了。是不是已經有點迫不及待想直到大牛們都是怎么來做的了?
?這里將中間調用的幾個簡單的過程跳過,熟悉Java的一眼就能看懂,直接進入發送消息時最核心的部分,
我們都知道Handler發送消息其實是將Message先放入到了MessageQueue,能看到該文章的我默認大家都已經很熟悉
Handler的基本原理了,如果又不熟悉的,可以參考
Handler消息機制原理全方文解讀
?此處直接看Message放入MessageQueue的過程:
boolean enqueueMessage(Message msg, long when) {
...//代碼較多,省去了部分拋出異常的代碼
synchronized (this) {
...
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;
}
?重點就在if-else這里,將它們一個一個拆開來看:
if (p == null || when == 0 || when < p.when) {//p是當前MessageQueue隊首Message
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
}
?如果當前隊列沒有其他需要發送的Message;或者當前新添加進來的的Message的時間點為0(即需要立即發送的消息);
或者當前新添加進來的的Message需要發送的時間點小與當前MessageQueue隊列頭部Message的時間點(即當前添加進來的Message需要在當前MessageQueue隊列頭部Message之前被發送)時,就會進入到if代碼塊里面。此時做的事情是將當前新添加的Message插入到了MessageQueue的隊首(看不懂是如何插入的可以參考Handler消息機制原理全方文解讀,
Message 的存儲是鏈表的形式,next相當于鏈表的尾指針)。
?這里還有一個賦值操作(needWake = mBlocked),這里解釋下,可以看到代碼里也有注釋,新的首部,然后如果阻塞了,需要喚醒線程。為什么會有線程的阻塞呢?其實MessageQueue內部的消息是按需要發送的時間點從小到大排列的,后面會分析到,從當前if里的when判斷也能看出一二,當隊首的Message未到達發送的時間點時,說明其當前所有的消息都未到達發送的時間,上面說過,Handler發送消息并不是通過定時器發送的,所以,當隊首Message(最近需要發送的Message)未到達發送時間點時,線程被阻塞,所以這里需要根據線程是否阻塞看是否需要喚醒線程,這樣才能使新加入的Message能及時發送出去,不會被阻塞。線程的喚醒是通過native的方法來實現的。
?接著來看下else里面的代碼:
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;
?執行到了else語句里面,說明了當前添加進來的Message是在當前MessqgeQueue隊首的Message之后才會被發送的,上邊分析if部分代碼的時候說過了Message是按需要發送的時間先后排列在MessageQueue中的,這里的for循環實際操作就是找到MessageQueue中比當前添加進來的Message需要發送的時間點大的位置,將Message插入到其前邊(實際就是一個鏈表的插入操作)。
?本章分析到這里就先告一段落了,之后會再詳細的分析Message從MessageQueue的取出過程,可以先參考Handler消息機制原理全方文解讀。
之所以寫這篇文章主要是為了解答兩個問題。
- sendMessageDelayed是如何實現延時發送消息的?
- sendMessageDelayed是通過阻塞來達到了延時發送消息的結果,那么會不會阻塞新添加的Message?
總結:
- Handler在發送消息的時候,MessageQueue里的消息是按照發送時間點從小到大排列的,
如果最近的Message未到達發送的時間則阻塞。 - 新加入的數據會根據時間點的大小判斷需要插入的位置,同時還需要判斷是否需要喚醒線程去發送當前的隊首的消息。