消息發(fā)送
創(chuàng)建消息
創(chuàng)建消息使用下面的代碼:
Message msg = Message.obtain(); // 實(shí)例化消息對(duì)象
msg.what = 1; // 消息標(biāo)識(shí)
msg.obj = "AA"; // 消息內(nèi)容存放
handler.sendMessage(msg);
創(chuàng)建消息,獲取Message對(duì)象,最好的方法是調(diào)用Message.obtain(),而不是直接通過(guò)new Message()的方式,因?yàn)镸essage.obtain()是從一個(gè)可回收的對(duì)象池中獲取Message對(duì)象,避免了重復(fù)創(chuàng)建。
關(guān)于Message的源碼分析可以看下這篇文章:
Messgae源碼分析
發(fā)送消息
查看一下Handler的類結(jié)構(gòu)圖:


Handler發(fā)送消息主要有sendMessage和post兩種方案,
- send方案發(fā)送消息
- sendMessage(Message) 立即發(fā)送Message到消息隊(duì)列
- sendMessageAtFrontOfQueue(Message) 立即發(fā)送Message到隊(duì)列,而且是放在隊(duì)列的最前面
- sendMessageAtTime(Message,long) 設(shè)置時(shí)間,發(fā)送Message到隊(duì)列
- sendMessageDelayed(Message,long) 延時(shí)若干毫秒后,發(fā)送Message到隊(duì)列
- post方案
- post(Runnable) 立即發(fā)送Message到消息隊(duì)列
- postAtFrontOfQueue(Runnable) 立即發(fā)送Message到隊(duì)列,而且是放在隊(duì)列的最前面
- postAtTime(Runnable,long) 設(shè)置時(shí)間,發(fā)送Message到隊(duì)列
- postDelayed(Runnable,long) 在延時(shí)若干毫秒后,發(fā)送Message到隊(duì)列
下面先從send方案中的第一個(gè)sendMessage() 開(kāi)始源碼跟蹤。
send方式
sendMessage()
發(fā)送消息在執(zhí)行了handler.sendMessage(msg)之后,我們往下追蹤源碼。
調(diào)用了下面的方法:
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
繼續(xù)調(diào)用了sendMessageDelayed(msg, 0)方法:
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
發(fā)現(xiàn)繼續(xù)調(diào)用了sendMessageAtTime()方法,繼續(xù)往下看:
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
// 1
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
// 2
return enqueueMessage(queue, msg, uptimeMillis);
}
這個(gè)方法主要做了兩件事,
- 1、獲取消息隊(duì)列,并對(duì)該消息隊(duì)列做非空判斷,如果為null,直接返回。
- 2、調(diào)用了enqueueMessage()方法,第一步獲取的消息隊(duì)列也作為了參數(shù)。
enqueueMessage()
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
// 1
msg.target = this;
// 2
if (mAsynchronous) {
msg.setAsynchronous(true);
}
// 3
return queue.enqueueMessage(msg, uptimeMillis);
}
主要做了三件事:
- 1、msg.target = this,設(shè)置了msg的target變量,將target指向自己。查看Message.java的源碼,target實(shí)際上是Handler對(duì)象。
- 2、mAsynchronous是控制著Handler發(fā)送同步異步消息的,在這里先簡(jiǎn)單提一下異步的作用,這里的異步主要是針對(duì)Message中的障柵(Barrier),當(dāng)出現(xiàn)障柵(Barrier)時(shí),同步消息會(huì)被阻塞,而異步消息不會(huì)被阻塞。后面會(huì)有單獨(dú)的文章介紹Handler的同步消息和異步消息。這里mAsynchronous為false,mAsynchronous是控制著Handler發(fā)送異步消息的,在Handler初始化時(shí),在Handler構(gòu)造方法里,傳了false:
public Handler() {
this(null, false);
}
在下面Handler的構(gòu)造方法里,將mAsynchronous設(shè)置為false。
public Handler(Callback callback, boolean async) {
......省略代碼
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
3、調(diào)用MessageQueue的enqueueMessage()方法。
繼續(xù)看enqueueMessage()方法。
boolean enqueueMessage(Message msg, long when) {
// 1 判斷msg的target變量是否為null,如果為null則拋出異常
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
// 2 判斷msg的標(biāo)志位,此時(shí)msg應(yīng)該是要入隊(duì),msg的標(biāo)志位應(yīng)該是還未被使用,如果是已使用狀態(tài),很明顯是有問(wèn)題的,直接拋出異常
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
// 3 加入同步鎖
synchronized (this) {
// 4 判斷消息隊(duì)列是否是關(guān)閉狀態(tài),如果是關(guān)閉狀態(tài),return false消息入隊(duì)失敗,并且回收消息
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;
}
// 5 設(shè)置msg的when,修改msg的標(biāo)志位為已使用狀態(tài)
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
// 6 主要是用來(lái)判斷要入隊(duì)的msg是否位于隊(duì)列頭部。第一個(gè)msg時(shí),mMessages為null,所以該msg應(yīng)該位于頭部
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
// 把msg的下一個(gè)元素設(shè)置為p,p是mMessages,mMessages此
//時(shí)為null,所以第一個(gè)message的next指向了null
msg.next = p;
// 把msg設(shè)置為鏈表的頭部元素
mMessages = msg;
// needWake需要根據(jù)mBlocked的情況考慮是否觸發(fā),如果有阻
// 塞,則需要喚醒,讓它立刻去拿消息處理
needWake = mBlocked;
} else { // 7 如果上面三個(gè)條件都不滿足則說(shuō)明要把msg插入到中間的位置
// 8 ,如果頭部元素不是障柵(barrier)或者異步消息,而且還是插入
// 中間的位置,我們是不喚醒消息隊(duì)列的
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
// 9 不斷遍歷消息隊(duì)列,根據(jù)when的比較找到合適的插入
// Message的位置
for (;;) {
// 設(shè)置前一個(gè)message指針
prev = p;
// 設(shè)置下一個(gè)message指針
p = p.next;
// 10
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
// 11
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
// 12
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
- 第一步,判斷msg的target變量是否為null,如果為null則拋出異常。
- 第二步,判斷msg的標(biāo)志位,此時(shí)msg應(yīng)該是要入隊(duì),msg的標(biāo)志位應(yīng)該是還未被使用,如果是已使用狀態(tài),很明顯是有問(wèn)題的,直接拋出異常。
- 第三步,加入同步鎖。
- 第四步,判斷消息隊(duì)列是否是關(guān)閉狀態(tài),如果是關(guān)閉狀態(tài),return false消息入隊(duì)失敗,并且回收消息。
- 第五步,設(shè)置msg的when,修改msg的標(biāo)志位為已使用狀態(tài)。
- 第六步,主要是用來(lái)判斷要入隊(duì)的msg是否位于隊(duì)列頭部。如果p==null則說(shuō)明msg是消息隊(duì)列的第一個(gè)消息;when == 0 表示立即執(zhí)行;when< p.when 表示 msg的執(zhí)行時(shí)間早與鏈表中的頭部元素的時(shí)間,所以上面三個(gè)條件,哪個(gè)條件成立,都要把msg設(shè)置成消息隊(duì)列中鏈表的頭部是元素。
- 第七步,如果上面三個(gè)條件都不滿足則說(shuō)明要把msg插入到中間的位置。
- 第八步,如果頭部元素不是障柵(barrier)或者異步消息,而且還是插入中間的位置,我們是不喚醒消息隊(duì)列的。
- 第九步,進(jìn)入一個(gè)死循環(huán),mMessages是第一個(gè)message,prev = p,將p的值賦值給prev,前面p指mMessage,所以此處prev指向了mMessage,即隊(duì)列中的第一個(gè)message。p = p.next,p指向了隊(duì)列中的第二個(gè)message,以此類推,實(shí)現(xiàn)了消息指針的移動(dòng)。
- 第十步,跳出循環(huán)條件,p==null,說(shuō)明沒(méi)有下一個(gè)元素,即消息隊(duì)列到末尾了。p!=null&&when < p.when 說(shuō)明當(dāng)前需要入隊(duì)的這個(gè)message的執(zhí)行時(shí)間是小于小于隊(duì)列中p指向的message的執(zhí)行時(shí)間的,也就是說(shuō)這個(gè)需要入隊(duì)的message比p指向的message先執(zhí)行,說(shuō)明這個(gè)位置剛好是這個(gè)入隊(duì)的message的,這樣就跳出循環(huán)。
- 第十一步,跳出循環(huán)后,主要做了兩件事,第一,將入隊(duì)的這個(gè)msg的next指向循環(huán)中獲取到的應(yīng)該排在這個(gè)消息之后的message。第二,將msg前面的message.next指向了msg。這樣msg就完成了入隊(duì)。
- 第十二步,如果需要喚醒,則喚醒,調(diào)用native的方法。
整個(gè)流程可以用下面的圖片表示:



總結(jié):遍歷消息隊(duì)列中的所有消息,根據(jù)when的比較,找到合適的message的入隊(duì)位置。
sendMessageAtFrontOfQueue()
查看源碼:
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);
}
和sendMessageAtTime()大體上一樣,唯一的區(qū)別是該方法在調(diào)用enqueueMessage()方法時(shí),最后一個(gè)參數(shù)是0。
查看MessageQueue的enqueueMessage()方法發(fā)現(xiàn),當(dāng)when==0時(shí),會(huì)一直走if語(yǔ)句的內(nèi)容,msg會(huì)一直插在消息隊(duì)列的頭部。
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{
......省略代碼
}
sendEmptyMessage
sendEmptyMessage()方法,調(diào)用了sendEmptyMessageDelayed()方法
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
sendEmptyMessageDelayed()方法,內(nèi)阻組裝了一個(gè)僅有what的Message,然后調(diào)用sendMessageDelayed(),從這不開(kāi)始就跟sendMessage()往后的流程相同。
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
sendEmptyMessageAtTime
查看源碼,直接調(diào)用了sendEmptyMessageAtTime()。
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageAtTime(msg, uptimeMillis);
}
以上就是發(fā)送消息的send方案,最終都會(huì)走向了enqueueMessage()方法。

post方式
查看post方式的源碼,可以看到,在方法內(nèi)部,還是調(diào)用了sendMessageDelayed()方法,最終也會(huì)走到上面的send流程,最終調(diào)用enqueueMessage()方法。這其中有個(gè)getPostMessage()方法。
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
查看getPostMessage()的源碼
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
這個(gè)方法主要做了兩件事:
- 通過(guò)Message.obtain()從消息對(duì)象池中獲取一個(gè)空的messgae
- 將這個(gè)空的message的callback變量指向Runnable
所以我們知道boolean post(Runnable r)方法的內(nèi)置也是通過(guò)Message.obtain()來(lái)獲取一個(gè)Message對(duì)象m,然后僅僅把m的callback指向參數(shù)r而已。最后最終通過(guò)調(diào)用send方案的某個(gè)流程最終調(diào)用到boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)。
總結(jié)
Handler的發(fā)送消息,無(wú)論是通過(guò)send方案還是pos方案最終都會(huì)做走到 boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)中。