- 1沙峻、Handler發(fā)送消息
- 2屏鳍、Handler的send方案
- 3悯森、Handler的post方案
1 Handler發(fā)送消息
- send方案發(fā)送消息(需要回調(diào)才能接收消息)
- sendMessage(Message) 立即發(fā)送Message到消息隊(duì)列
- sendMessageAtFrontOfQueue(Message) 立即發(fā)送Message到隊(duì)列盅蝗,而且是放在隊(duì)列的最前面
- sendMessageAtTime(Message,long) 設(shè)置時間,發(fā)送Message到隊(duì)列
- sendMessageDelayed(Message,long) 延時若干毫秒后呢袱,發(fā)送Message到隊(duì)列
- post方案 立即發(fā)送Message到消息隊(duì)列
- post(Runnable) 立即發(fā)送Message到消息隊(duì)列
- postAtFrontOfQueue(Runnable) 立即發(fā)送Message到隊(duì)列官扣,而且是放在隊(duì)列的最前面
- postAtTime(Runnable,long) 設(shè)置時間,發(fā)送Message到隊(duì)列
- postDelayed(Runnable,long) 在延時若干毫秒后羞福,發(fā)送Message到隊(duì)列
2 Handler的send方案
以Handler的sendMessage(Message msg)為例子
2.1 sendMessage(Message msg)方法
代碼在Handler.java 505行
/**
* Pushes a message onto the end of the message queue after all pending messages
* before the current time. It will be received in {@link #handleMessage},
* in the thread attached to this handler.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
- 在當(dāng)前時間惕蹄,在所有待處理消息之后,將消息推送到消息隊(duì)列的末尾坯临。在和當(dāng)前線程關(guān)聯(lián)的的Handler里面的handleMessage將收到這條消息
2.1.1 boolean sendMessageDelayed(Message msg, long delayMillis)
代碼在Handler.java 565行
/**
* Enqueue a message into the message queue after all pending messages
* before (current time + delayMillis). You will receive it in
* {@link #handleMessage}, in the thread attached to this handler.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the message will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*/
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
該方法內(nèi)部就做了兩件事
- 1焊唬、判斷delayMillis是否小于0
- 2、調(diào)用了public boolean sendMessageAtTime(Message msg, long uptimeMillis)方法
2.1.2 boolean sendMessageAtTime(Message msg, long uptimeMillis)
代碼在Handler.java 592行
/**
* Enqueue a message into the message queue after all pending messages
* before the absolute time (in milliseconds) <var>uptimeMillis</var>.
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
* Time spent in deep sleep will add an additional delay to execution.
* You will receive it in {@link #handleMessage}, in the thread attached
* to this handler.
*
* @param uptimeMillis The absolute time at which the message should be
* delivered, using the
* {@link android.os.SystemClock#uptimeMillis} time-base.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the message will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*/
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)的SystemClock的uptimeMillis()為基準(zhǔn)看靠,以毫秒為基本單位的絕對時間下赶促,在所有待處理消息后,將消息放到消息隊(duì)列中挟炬。
- 深度睡眠中的時間將會延遲執(zhí)行的時間鸥滨,你將在和當(dāng)前線程辦的規(guī)定的Handler中的handleMessage中收到該消息。
- 因?yàn)橥ǔN覀兝斫獾漠惒绞侵感麻_一個線程谤祖,但是這里不是婿滓,因?yàn)楫惒降囊彩前l(fā)送到looper所綁定的消息隊(duì)列中,這里的異步主要是針對Message中的障柵(Barrier)而言的粥喜,當(dāng)出現(xiàn)障柵(Barrier)的時候凸主,同步的會被阻塞,而異步的則不會额湘。所以這個異步僅僅是一個標(biāo)記而已卿吐。
該方法內(nèi)部就做了兩件事
- 1旁舰、獲取消息隊(duì)列,并對該消息隊(duì)列做非空判斷嗡官,如果為null箭窜,直接返回false,表示消息發(fā)送失敗
- 2衍腥、調(diào)用了boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)方法
2.1.3 boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)
代碼在Handler.java 626行
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變量磺樱,并將target指向自己
- 如果Handler的mAsynchronous值為true(默認(rèn)為false,即不設(shè)置)婆咸,則設(shè)置msg的flags值竹捉,讓是否異步在Handler和Message達(dá)成統(tǒng)一。
- 調(diào)用MessageQueue的enqueueMessage()方法
2.1.4 boolean enqueueMessage(Message msg, long when)方法
代碼在MessageQueue.java 533行
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) {
// 第四步
//判斷消息隊(duì)列是否正在關(guān)閉
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;
// 第六步
//根據(jù)when的比較來判斷要添加的Message是否應(yīng)該放在隊(duì)列頭部擅耽,當(dāng)?shù)谝粋€添加消息的時候活孩,
// 測試隊(duì)列為空物遇,所以該Message也應(yīng)該位于頭部乖仇。
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
// 把msg的下一個元素設(shè)置為p
msg.next = p;
// 把msg設(shè)置為鏈表的頭部元素
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.
//除非消息隊(duì)列的頭部是障柵(barrier)询兴,或者消息隊(duì)列的第一個消息是異步消息乃沙,
//否則如果是插入到中間位置,我們通常不喚醒消息隊(duì)列诗舰,
// 第八步
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;
}
// 第十三步
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
// 第十四步
return true;
}
- 第1步驟眶根、 判斷msg的target變量是否為null蜀铲,如果為null,則為障柵(barrier)属百,而障柵(barrier)入隊(duì)則是通過postSyncBarrier()方法入隊(duì)记劝,所以msg的target一定有值
- 第2步驟、 判斷msg的標(biāo)志位族扰,因?yàn)榇藭r的msg應(yīng)該是要入隊(duì)厌丑,意味著msg的標(biāo)志位應(yīng)該顯示還未被使用。如果顯示已使用渔呵,明顯有問題怒竿,直接拋異常。
- 第3步驟扩氢、 加入同步鎖耕驰。
- 第4步驟、 判斷消息隊(duì)列是否正在被關(guān)閉录豺,如果是正在被關(guān)閉朦肘,則return false告訴消息入隊(duì)是失敗托嚣,并且回收消息
- 第5步驟、 設(shè)置msg的when并且修改msg的標(biāo)志位厚骗,msg標(biāo)志位顯示為已使用
- 第6步驟示启、 如果p==null則說明消息隊(duì)列中的鏈表的頭部元素為null;when == 0 表示立即執(zhí)行领舰;when< p.when 表示 msg的執(zhí)行時間早與鏈表中的頭部元素的時間夫嗓,所以上面三個條件,那個條件成立冲秽,都要把msg設(shè)置成消息隊(duì)列中鏈表的頭部是元素
- 第7步驟舍咖、 如果上面三個條件都不滿足則說明要把msg插入到中間的位置,不需要插入到頭部
- 第8步驟锉桑、 如果頭部元素不是障柵(barrier)或者異步消息排霉,而且還是插入中間的位置,我們是不喚醒消息隊(duì)列的民轴。
- 第9步驟攻柠、 進(jìn)入一個死循環(huán),將p的值賦值給prev后裸,前面的帶我們知道瑰钮,p指向的是mMessage,所以這里是將prev指向了mMessage微驶,在下一次循環(huán)的時候浪谴,prev則指向了第一個message,一次類推因苹。接著講p指向了p.next也就是mMessage.next苟耻,也就是消息隊(duì)列鏈表中的第二個元素。這一步驟實(shí)現(xiàn)了消息指針的移動扶檐,此時p表示的消息隊(duì)列中第二個元素凶杖。
- 第10步驟、 p==null蘸秘,則說明沒有下一個元素官卡,即消息隊(duì)列到頭了,跳出循環(huán)醋虏;p!=null&&when < p.when 則說明當(dāng)前需要入隊(duì)的這個message的執(zhí)行時間是小于隊(duì)列中這個任務(wù)的執(zhí)行時間的寻咒,也就是說這個需要入隊(duì)的message需要比隊(duì)列中這個message先執(zhí)行,則說明這個位置剛剛是適合這個message的颈嚼,所以跳出循環(huán)毛秘。 如果上面的兩個條件都不滿足,則說明這個位置還不是放置這個需要入隊(duì)的message,則繼續(xù)跟鏈表中后面的元素叫挟,也就是繼續(xù)跟消息隊(duì)列中的下一個消息進(jìn)行對比艰匙,直到滿足條件或者到達(dá)隊(duì)列的末尾。
- 第11步驟抹恳、 因?yàn)闆]有滿足條件员凝,說明隊(duì)列中還有消息,不需要喚醒奋献。
- 第12步驟健霹、 跳出循環(huán)后主要做了兩件事:事件A,將入隊(duì)的這個消息的next指向循環(huán)中獲取到的應(yīng)該排在這個消息之后message瓶蚂。事件B糖埋,將msg前面的message.next指向了msg。這樣就將一個message完成了入隊(duì)窃这。
- 第13步驟瞳别、 如果需要喚醒,則喚醒杭攻,具體請看后面的Handler中的Native詳解祟敛。
- 第14步驟、 返回true朴上,告知入隊(duì)成功垒棋。
插入消息后,有條件地執(zhí)行nativeWake去喚醒epoll痪宰。needWake的值依賴mBlocked——當(dāng)進(jìn)入next()方法時沒有待處理的消息,mBlock為true畔裕,有消息并返回到looper時衣撬,mBlock為false。
結(jié)合next()和enqueueMessage()方法扮饶,得知nativeWake被調(diào)用的條件為:
- next()方法在等待新消息具练,且新插入消息的為鏈表頭時。needWake為true
- 設(shè)置了Sync Barrier甜无,且插入的消息是“異步”的扛点。needWake為true
2.2 boolean sendMessageAtFrontOfQueue(Message msg)
代碼在Handler.java 615行
/**
* Enqueue a message at the front of the message queue, to be processed on
* the next iteration of the message loop. You will receive it in
* {@link #handleMessage}, in the thread attached to this handler.
* <b>This method is only for use in very special circumstances -- it
* can easily starve the message queue, cause ordering problems, or have
* other unexpected side-effects.</b>
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
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ì)列的最前面插入一個消息,在消息循環(huán)的下一次迭代中進(jìn)行處理岂丘。
- 由于它可以輕松的解決消息隊(duì)列的排序問題和其他的意外副作用陵究。
方法內(nèi)部的實(shí)現(xiàn)和boolean sendMessageAtTime(Message msg, long uptimeMillis)大體上一致,唯一的區(qū)別就是該方法在調(diào)用enqueueMessage(MessageQueue, Message, long)方法的時候奥帘,最后一個參數(shù)是0而已铜邮。
2.3 boolean sendEmptyMessage(int what)
代碼在Handler.java 517行
/**
* Sends a Message containing only the what value.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
發(fā)送一個僅有what的Message
boolean sendEmptyMessageDelayed(int what, long delayMillis)
代碼在Handler.java 531行
/**
* Sends a Message containing only the what value, to be delivered
* after the specified amount of time elapses.
* @see #sendMessageDelayed(android.os.Message, long)
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
- 發(fā)送一個僅有what的Message,并且延遲特定的時間發(fā)送
- 這個方法內(nèi)部主要就是做了3件事
1、調(diào)用Message.obtain();從消息對象池中獲取一個空的Message松蒜。
2扔茅、設(shè)置這個Message的what值
3、調(diào)用sendMessageDelayed(Message,long) 將這個消息方法
2.4 boolean sendEmptyMessageAtTime(int what, long uptimeMillis)
代碼在Handler.java 547行
/**
* Sends a Message containing only the what value, to be delivered
* at a specific time.
* @see #sendMessageAtTime(android.os.Message, long)
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageAtTime(msg, uptimeMillis);
}
- 發(fā)送一個僅有what的Message秸苗,并且在特定的時間發(fā)送
- 這個方法內(nèi)部主要就是做了3件事
- 1召娜、調(diào)用Message.obtain();從消息對象池中獲取一個空的Message。
- 2惊楼、設(shè)置這個Message的what值
- 3萤晴、調(diào)用sendMessageAtTime(Message,long) 將這個消息方法
2.5 小結(jié)
這些send方案都會從這里或者那里最終走到boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)
3 Handler的post方案
3.1 boolean post(Runnable r)方法
代碼在Handler.java 324行
/**
* Causes the Runnable r to be added to the message queue.
* The runnable will be run on the thread to which this handler is
* attached.
*
* @param r The Runnable that will be executed.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
將一個Runnable添加到消息隊(duì)列中,這個runnable將會在和當(dāng)前Handler關(guān)聯(lián)的線程中被執(zhí)行胁后。
就是調(diào)用了sendMessageDelayed(Message, long);這個方法店读,所以可見boolean post(Runnable r)這個方法最終還是走到上面說到的send的流程中
最終調(diào)用boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)。
3.1.1 Message getPostMessage(Runnable r)方法
代碼在Handler.java 725行
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
代碼很簡單攀芯,主要是做了兩件事
- 通過Message.obtain()從消息對象池中獲取一個空的Message
- 將這空的Message的callback變量指向Runnable
最后返回這個Message m屯断。
3.1.2 小結(jié)
- boolean post(Runnable r)方法的內(nèi)置也是通過Message.obtain()來獲取一個Message對象m,然后僅僅把m的callback指向參數(shù)r而已侣诺。
- 最后最終通過調(diào)用send方案的某個流程最終調(diào)用到boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)
3.2 boolean postAtTime(Runnable r, long uptimeMillis)方法
代碼在Handler.java 347行
/**
* Causes the Runnable r to be added to the message queue, to be run
* at a specific time given by <var>uptimeMillis</var>.
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
* Time spent in deep sleep will add an additional delay to execution.
* The runnable will be run on the thread to which this handler is attached.
*
* @param r The Runnable that will be executed.
* @param uptimeMillis The absolute time at which the callback should run,
* using the {@link android.os.SystemClock#uptimeMillis} time-base.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the Runnable will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*/
public final boolean postAtTime(Runnable r, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
- 將一個Runnable添加到消息隊(duì)列中殖演,這個runnable將會一個特定的時間被執(zhí)行,這個時間是以android.os.SystemClock.uptimeMillis()為基準(zhǔn)年鸳。
- 如果在深度睡眠下趴久,會推遲執(zhí)行的時間,這個Runnable將會在和當(dāng)前Hander關(guān)聯(lián)的線程中被執(zhí)行搔确。
- 方法內(nèi)部也是先是調(diào)用getPostMessage(Runnable)來獲取一個Message彼棍,這個Message的callback字段指向了這個Runnable,然后調(diào)用sendMessageAtTime(Message,long)膳算。
3.3 boolean postAtTime(Runnable r, Object token, long uptimeMillis)方法
代碼在Handler.java 372行
/**
* Causes the Runnable r to be added to the message queue, to be run
* at a specific time given by <var>uptimeMillis</var>.
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
* Time spent in deep sleep will add an additional delay to execution.
* The runnable will be run on the thread to which this handler is attached.
*
* @param r The Runnable that will be executed.
* @param uptimeMillis The absolute time at which the callback should run,
* using the {@link android.os.SystemClock#uptimeMillis} time-base.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the Runnable will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*
* @see android.os.SystemClock#uptimeMillis
*/
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}
- 這個方法和上個方法唯一不同就是多了Object參數(shù)座硕,而這個參數(shù)僅僅是把Message.obtain();獲取的Message的obj字段的指向第二個入?yún)oken而已。最后也是調(diào)用sendMessageAtTime(Message,long)涕蜂。
2.4 boolean postDelayed(Runnable r, long delayMillis)方法
代碼在Handler.java 396行
/**
* Causes the Runnable r to be added to the message queue, to be run
* after the specified amount of time elapses.
* The runnable will be run on the thread to which this handler
* is attached.
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
* Time spent in deep sleep will add an additional delay to execution.
*
* @param r The Runnable that will be executed.
* @param delayMillis The delay (in milliseconds) until the Runnable
* will be executed.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the Runnable will be processed --
* if the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*/
public final boolean postDelayed(Runnable r, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
這個方法也很簡單华匾,就是依舊是通過getPostMessage(Runnable)來獲取一個Message,最后調(diào)用sendMessageDelayed(Message,long)而已机隙。
3.5 boolean postAtFrontOfQueue(Runnable r)方法
代碼在Handler.java 416行
/**
* Posts a message to an object that implements Runnable.
* Causes the Runnable r to executed on the next iteration through the
* message queue. The runnable will be run on the thread to which this
* handler is attached.
* <b>This method is only for use in very special circumstances -- it
* can easily starve the message queue, cause ordering problems, or have
* other unexpected side-effects.</b>
*
* @param r The Runnable that will be executed.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean postAtFrontOfQueue(Runnable r)
{
return sendMessageAtFrontOfQueue(getPostMessage(r));
}
就是依舊是通過getPostMessage(Runnable)來獲取一個Message蜘拉,最后調(diào)用sendMessageAtFrontOfQueue(Message)而已。
3.6 小結(jié)
- Handler的post方案:都是通過Message getPostMessage(Runnable )中調(diào)用Message m = Message.obtain();來獲取一個空的Message有鹿,然后把這個Message的callback變量指向了Runnable旭旭,最終調(diào)用相應(yīng)的send方案而已。
所以我們可以這樣說:
Handler的發(fā)送消息(障柵除外)印颤,無論是通過send方案還是pos方案最終都會做走到 boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) 中