前言
Handler 是Android 的消息處理機制,其主要有兩個作用:
1.發送消息,延遲處理。你可以通過Handler 來發送一個Message 或者Runnable 對象,並在收到消息時處理他們,另外可以指定延遲時間,以便在將來執行。
2.線程間通訊。簡單來說就是在不同於Handler 所屬的線程發送消息,在Handler 的依附線程中接受並處理消息。這也就要求Handler 實例必須與線程和線程的消息隊列相關聯,當創建一個新的Handler對象時,需要綁定到創建它的線程和線程的消息隊列上,通過將Message/Runnable 添加到消息隊列中,在它們從消息隊列中出來時執行。
Handler 是整個消息機制的門面類,用來發送和接收消息。提供了兩種形式的消息分發和處理,一種是post 一個Runnable 對象,另外一種是send 一個Message對象。
基本使用
發送和處理Runnable
Handler 支持通過 post 的相關方法來發送一個 Runnable 對象進入消息隊列,當收到相應的消息時被調用。相關的方法有{@link #post}, {@link #postAtTime(Runnable, long)}, {@link #postDelayed}
Handler handler = new Handler();
Runnable runnable = new Runnable() {
@Override
public void run() {
// todo something
}
}
// 立即發送
handler.post(runnable);
其他API介紹:
android.os.Handler#postDelayed(java.lang.Runnable, long)
將Runnable 添加到消息隊裏中,並在指定的延遲後執行
android.os.Handler#postAtTime(java.lang.Runnable, long)
將Runnable 添加到消息隊裏中,並在指定的時間執行
發送和處理Message
Handler 允許發送一個 message對象,實現 Handler的{@link #handleMessage}方法,在這裏處理接收到的Message。相關的方法有{@link #sendEmptyMessage}, {@link #sendMessage}, {@link #sendMessageAtTime}, {@link #sendMessageDelayed} 等
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// 處理消息 message
}
};
// 獲取 message
Message message = mHandler.obtainMessage(0);
// 發送 message
mHandler.sendMessage(message);
其他API介紹:
android.os.Handler#sendMessageDelayed
將Message 添加到消息隊裏中,並在指定的延遲後發送,在handler的 handleMessage 中處理消息
android.os.Handler#sendMessageAtTime
將Message 添加到消息隊裏中,並在指定的延遲後發送,在handler的 handleMessage 中處理消息
流程梳理
使用Handler 發送一個Message時,在 MessageQueue 的enqueueMessage 方法中會對消息按時間優先級進行入隊操作。
與線程綁定的Looper 不斷的從MessageQueue中取消息進行發送(queue.next()),當某個Message 執行完畢後,釋放資源並加入到緩存隊列中以重複使用(msg.recycleUnchecked())
獲取消息
雖然Message的構造函數是公共的,我們可以通過new 關鍵字來自行創建一個Message 對象,但是系統更推薦我們使用 {Message.obtain()}或{Handler#obtainMessage.obtainMessage()}相關的方法獲取對象。
Handler 的消息獲取內部採用了享元模式來實現,Message 內部有一個全局的緩存池sPool,保存着回收的Message 對象。當使用obtain() 方法時,會先從緩存池中獲取Message 對象,如果沒有再去創建一個新對象。在消息轉發完成後,會對使用的消息進行回收再利用,節約因頻繁創建對象帶來的內存開銷。
發送消息
Handler 提供了很多的 send 和post 的方法,這些方法最終都會走到android.os.Handler#enqueueMessage 這個方法,而在這個方法裏又會調用MessageQueue 的enqueueMessage 方法執行消息的入隊操作。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
消息入隊
MessageQueue 內部維護了一個消息隊列,而 enqueueMessage(Message msg, long when) 方法主要處理的就是入隊操作,對新來的Message 根據絕對時間進行優先級排序,絕對時間小的Message往前排。
boolean enqueueMessage(Message msg, long when) {
...省略其他代碼
msg.when = when;
Message p = mMessages;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
} else {
...省略其他代碼
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
...省略其他代碼
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
...省略其他代碼
}
消息出隊
在Handler 機制中,Looper類的主要作用是負責線程的消息循環,在Looper.loop() 方法中,循環不斷的從MessageQueue.next() 函數中獲取下一個消息進行派發,在發送完畢後回收釋放該消息,完成消息的出隊。
public static void loop() {
final Looper me = myLooper();
...省略其他代碼
final MessageQueue queue = me.mQueue;
for (;;) {
// 從消息隊列中獲取下一個要執行的Message
Message msg = queue.next(); // might block
...省略其他代碼
// 執行消息的分發
msg.target.dispatchMessage(msg);
...省略其他代碼
// 釋放、回收Message,完成消息出隊
msg.recycleUnchecked();
}
}
理解
Handler:是消息機制的門面類,主要負責發送和處理消息,同樣還有移除消息的功能。
Message:即要發送的消息,包含消息標記、消息數據、執行時間、處理響應的Handler等。
MessageQueue:內部包含一個由Looper調度的消息隊列
Looper:負責線程的消息循環,從MessageQueue 中獲取要發送的消息
以一家運輸公司做個比喻
運輸公司(Handler):承接貨物的運輸業務,負責貨物的接受和發送。
運輸車(Message):貨物的載體,附帶一些信息,比如所屬公司(Handler)、編號(what)、運輸的貨物(arg1、arg2、obj)、發車時間(when)等等
備用車輛(Message.sPool):空閒狀態的運輸車,當有新需求的時候負責提供運輸車輛
執行運輸任務的車隊(MessageQueue.mMessages):因任務而組成的運輸車隊,根據每輛車發車時間進行車輛排序。
調度站(Looper):負責對運輸的車隊車輛進行逐個派發
當客戶有需求時,運輸公司會從空閒的運輸車中安排一輛車爲其服務,貨物打包好後加入執行運輸任務的車隊中。運輸車隊對新加入的運輸車輛按發車時間進行排序。另一邊,調度站如果發現有要執行任務的車隊,則逐個對運輸車輛進行派發,“下一輛、下一輛…”,如果沒有,則處於等待的狀態。運輸車輛執行完當前任務後,把攜帶的信息清空,加入到備用車輛中,以供下次繼續使用。
源碼分析
本篇先對Handler 機制做個大概的介紹,源碼部分將對Message、MessageQueue、Looper 分別做分析。