Android 消息機(jī)制深入源碼分析 [ 一 ]
Android 消息機(jī)制之 ThreadLocal 深入源碼分析 [ 二 ]
Android 消息機(jī)制之 Looper 深入源碼分析 [ 三 ]
Android 消息機(jī)制之 Message 與消息對象池的深入源碼分析 [ 四 ]
Android 消息機(jī)制之 MessageQueue 深入源碼分析 [ 五 ]
Android 消息機(jī)制之初識Handler [ 六 ]
Android 消息機(jī)制之 Handler 發(fā)送消息的深入源碼分析 [ 七 ]
Android 消息機(jī)制之 MessageQueue.next() 消息取出的深入源碼分析 [ 八 ]
Android 消息機(jī)制之消息的其他處理深入源碼分析 [ 九 ]
Android 消息機(jī)制總結(jié) [ 十 ]
上一章, 初步認(rèn)識了 Handler, 本章節(jié)將繼續(xù)接著上一章開始對消息的具體發(fā)送進(jìn)行學(xué)習(xí)和分析.
1. Handler 消息發(fā)送的分類
Handler 平時(shí)發(fā)送消息主要是調(diào)用兩大類方法, 分別是 send 方案 以及 post 方案
-
send 方案
boolean sendMessage(Message msg)
boolean sendEmptyMessage(int what)
boolean sendEmptyMessageDelayed(int what, long delayMillis)
boolean sendEmptyMessageAtTime(int what, long uptimeMillis)
boolean sendMessageDelayed(Message msg, long delayMillis)
boolean sendMessageAtTime(Message msg, long uptimeMillis)
boolean sendMessageAtFrontOfQueue(Message msg)
-
post 方案
boolean post(Runnable r)
boolean postAtFrontOfQueue(Runnable r)
boolean postAtTime(Runnable r, long uptimeMillis)
boolean postAtTime(Runnable r, Object token, long uptimeMillis)
boolean postDelayed(Runnable r, long delayMillis)
-
boolean postDelayed(Runnable r, Object token, long delayMillis)
?
?
2. send 方案.
還是先從 send 方案的第一個(gè)開始看, 也就是我們最常用的一個(gè).
2.1 boolean sendMessage(Message msg)
Handler.java 602 行.
public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg, 0);
}
- 官方注釋:
在當(dāng)前時(shí)間之前的所有掛起消息之后,將消息推送到消息隊(duì)列的末尾. 在和當(dāng)前線程關(guān)聯(lián)的
Handler
里面的HandlerMessage
將收到這條消息.
- 分析
代碼中就是簡單的調(diào)用了
sendMessageDelayed(msg, 0)
?
2.2 boolean sendMessageDelayed(Message msg, long delayMillis)
Handler.java 662 行.
public final boolean sendMessageDelayed(Message msg, long delayMillis){
//判斷 delayMillis 是否小于0
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
- 分析
如果傳入的延遲時(shí)間小于 0 , 那么就等于 0. 然后調(diào)用
sendMessageAtTime
傳入了SystemClock.uptimeMillis() + delayMillis
SystemClock.uptimeMillis()
= 從開機(jī)到現(xiàn)在的毫秒數(shù)(手機(jī)睡眠的時(shí)間不包括在內(nèi)).
?
2.3 boolean sendMessageAtTime(Message msg, long uptimeMillis)
Handler.java 689 行.
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);
}
- 官方注釋
在 Android 系統(tǒng)的重開機(jī)到現(xiàn)在的毫秒數(shù)為基準(zhǔn)的絕對時(shí)間下, 將消息放到所有的待處理消息后的隊(duì)列中. 深度睡眠中的時(shí)間將會(huì)延遲執(zhí)行的時(shí)間,(也就是說手機(jī)睡眠的時(shí)間不包括在內(nèi)), 你將在和當(dāng)前線程關(guān)聯(lián)的
Handler
里面的HandlerMessage
將收到這條消息.
- 分析
方法內(nèi)部做了兩件事情
- 獲取消息隊(duì)列, 并對消息隊(duì)列做非空判斷.,如果為
null
, 直接返回false
. (在 Handler 的構(gòu)造方法中, 會(huì)對消息隊(duì)列對象mQueue
進(jìn)行賦值)- 調(diào)用
enqueueMessage(queue, msg, uptimeMillis)
方法.
?
2.4 boolean enqueueMessagee(MessageQueue queue, Message msg, long uptimeMillis)
Handler.java 740 行.
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
- 分析
內(nèi)部做了三件事
- 設(shè)置
msg
的target
變量指向當(dāng)前Handler
- 如果當(dāng)前
Handler
是異步的, 則設(shè)置msg
也為異步. 讓Handler
與Message
達(dá)成一致. (在上一章 初識 Handler 中說過, 默認(rèn)是非異步的, 需要在創(chuàng)建 Handler 的時(shí)候指定為異步)- 調(diào)用
MessageQueue.enqueueMessage()
方法進(jìn)行消息入隊(duì) .
?
2.5 MessageQueue boolean enqueueMessage(Message msg, long when)
MessageQueue.java 536 行, 由于代碼過長, 將會(huì)分為多段來分析.
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.");
}
- 分析
- 判斷
msg
的target
變量是否為null
, 如果為null
,則會(huì)人會(huì)是障柵, 但是障柵的添加是通過postSyncBarrier
方式添加的(在本系列的第五章節(jié)有分析). 所以正常Message
的target
一定是有值的. 反之拋出異常.- 接著判斷
msg
的標(biāo)記為, 因?yàn)榇藭r(shí)的Message
是要入隊(duì), 意味著msg
的標(biāo)記位應(yīng)該是未被使用. 如果顯示已使用, 則拋出異常.
//第三步
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) {
//把 msg 的下一個(gè)元素設(shè)置為 p
msg.next = p;
//把 msg 設(shè)置為鏈表的頭部元素
mMessages = msg;
//如果有阻塞,則需要喚醒
needWake = mBlocked;
}
- 分析
- 加入同步鎖
- 判斷消息隊(duì)列是否正在關(guān)閉, 如果是, 直接返回
false
, 表示消息入隊(duì)失敗. 并且回收消息.- 設(shè)置
msg
的發(fā)送時(shí)間, 以及設(shè)置msg
正在使用的標(biāo)記位. 接著取出消息鏈表中頭部元素賦值給p
p == null
說明當(dāng)前要入隊(duì)的消息是第一個(gè)消息.when == 0
表示立即執(zhí)行.when < p.when
表示當(dāng)前要入隊(duì)msg
的執(zhí)行時(shí)間要早于消息鏈表頭部元素的執(zhí)行時(shí)間. 所以這三個(gè)條件, 無論哪個(gè)條件成立, 都會(huì)把當(dāng)前要入隊(duì)的msg
設(shè)置為消息鏈表的頭部.
//第七步
else {
//第八步
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
//第九步
//不斷遍歷消息隊(duì)列, 根據(jù) when 的比較找到合適的插入 message 的位置
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;
}
- 分析
- 如果以上三個(gè)條件都不滿足, 則說明要吧
msg
插入到消息鏈表中非頭部的位置.- 如果頭部元素是障柵或者是異步消息,而且還是插入中間位置,我們不會(huì)喚醒
mBlocked
這里先認(rèn)為是false
, 它的賦值是在MessageQueue.next()
方法中 , 如果當(dāng)前消息鏈表沒有消息, 或者未到執(zhí)行時(shí)間, 并且也沒有可執(zhí)行的空閑消息的時(shí)候, 會(huì)被賦值為true
, 并且消息隊(duì)列開始阻塞, 當(dāng)有可以立即執(zhí)行的消息的時(shí)候會(huì)被賦值為false
.
p.target == null
表示頭部元素是一個(gè)障柵.
msg.isAsynchronous()
當(dāng)前要入隊(duì)的消息是一個(gè)異步消息.- 進(jìn)入死循環(huán), 將
p
賦值給prev
, 那么prev
也指向了消息鏈表的頭部, 接著將p
指向了p.next
. 也就是鏈表中的第二個(gè)元素. 這兩個(gè)賦值操作, 實(shí)現(xiàn)了消息指針的移動(dòng).- 消息指針移動(dòng)過后,
p == null
, 說明沒有下一個(gè)元素了,when < p.when
則說明要入隊(duì)的這個(gè)消息的執(zhí)行時(shí)間是小于當(dāng)前p
指向消息的執(zhí)行時(shí)間的. 這兩個(gè)條件有一個(gè)成立說明現(xiàn)在這個(gè)位置適合插入要入隊(duì)的消息, 然后就跳出死循環(huán),- 若第 10 步?jīng)]有跳出循環(huán), 并且執(zhí)行到了 11 步, 那么說明沒有滿足條件, 隊(duì)列中還有消息, 不需要喚醒.
- 跳出循環(huán)后做了兩件事.
- 將要入隊(duì)的這個(gè)消息的
next
指向循環(huán)中獲取到應(yīng)該排在這個(gè)入隊(duì)消息之后的Message
.- 將要入隊(duì)的這個(gè)消息前面消息的
next
指向自己. 這樣就完成了入隊(duì)操作.
- 是否要喚醒.
- 入隊(duì)成功返回
true
?
以上就是我們常用的 sendMessage(Message msg)
消息發(fā)送流程, 接下來看 send
方案中剩下的.
2.5 boolean sendMessageAtFrontOfQueue(Message msg)
Handler.java 712 行.
public final boolean sendMessageAtFrontOfQueue(Message msg) {
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, 0);
}
- 官方翻譯
在消息隊(duì)列的最前面插入一個(gè)消息, 在消息循環(huán)的下一次迭代中進(jìn)行處理. 你將在當(dāng)前線程關(guān)聯(lián)的
Handler
的handleMessage()
中收到這個(gè)消息. 由于它可以輕松的解決消息的排序和其他的意外副作用.
- 解析
方法內(nèi)部的實(shí)現(xiàn)和
boolean sendMessageAtTime(Message msg, long uptimeMillis)
大體上一致. 唯一的區(qū)別就是該方法在調(diào)用入隊(duì)方法的時(shí)候, 最后一個(gè)參數(shù)是 0, 表示需要立即執(zhí)行.
?
剩下的 boolean sendEmptyMessage(int what)
與 boolean sendEmptyMessageDelayed(int what, long uptimeMillis)
就不再分析了, 非常簡單, 可以自己看一下.
?
send
方案的最后, 都是會(huì)調(diào)用 enqueueMessage() 入隊(duì)方法來完成消息的入隊(duì).
3. post 方案
3.1 boolean post(Runnable r)
Handler.java 393行.
public final boolean post(Runnable r){
return sendMessageDelayed(getPostMessage(r), 0);
}
- 官方注釋
將一個(gè)
Runnable
添加到消息隊(duì)列中, 這個(gè)Runnable
將會(huì)在和當(dāng)前Handler
關(guān)聯(lián)的線程中執(zhí)行.
-分析
這個(gè)方法內(nèi)部簡單, 就是調(diào)用了
sendMessageDelayed()
這個(gè)方法, 所以可見boolean post(Runnable r)
這個(gè)方法最終還是走到上面說的send
方案的流程中. 最后還是調(diào)用enqueueMessage()
入隊(duì)方案.
看一下調(diào)用的 getPostMessage(Runnable r)
?
3.1 Message getPostMessage(Runnable r)
Handler.java 859 行
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
- 分析
- 從消息對象池中獲取一個(gè)空的
Message
2.將空Message
的callback
指向Runnable
(這個(gè)Callback
是Message
中的Runnable
)
3.最后返回這個(gè)Message
由此我們可以得知 boolean post(Runnable r)
方法的內(nèi)部也是通過 Message.obtain
來獲取一個(gè) Message
對象. 然后僅僅只是把 Message
對象的 Runnable callback
賦值而已. 最后還是調(diào)用了 send
方案的某個(gè)流程最終調(diào)用到入隊(duì)方法.
后面剩余的 post
方法依舊如此, 只是調(diào)用的是不同的 send
方案中的方法.
?
4.消息發(fā)送總結(jié)
Handler
發(fā)送消息 (除障柵外), 無論是 send
還是 post
最終都會(huì)調(diào)用 MessageQueue.enqueueMessage(Message msg, long when)
方法進(jìn)行入隊(duì). 下圖展示了他們之間的關(guān)系.
消息發(fā)送出去了, 剩下的就是取出消息以及其他處理了, 將在下一章分析.