Handler 對(duì)于 Android 開發(fā)來說簡(jiǎn)直就是家常便飯,它的原理自然都很熟悉,這篇文章不會(huì)宏觀地去介紹它的原理,而是細(xì)節(jié)深入到各個(gè)組成。
目錄
關(guān)系
開始深入細(xì)節(jié)的時(shí)候,我們可以先復(fù)習(xí)下 Handler 、Looper 和 MessageQueue 三者的關(guān)系。
- Handler 必須在
Looper.prepare()之后才能創(chuàng)建使用 - Looper 與當(dāng)前線程關(guān)聯(lián),并且管理著一個(gè) MessageQueue
- Message 是實(shí)現(xiàn) Parcelable 接口的類
- 以一個(gè)線程為基準(zhǔn),他們的數(shù)量級(jí)關(guān)系是:
Handler(N) : Looper(1) : MessageQueue(1) : Thread(1)
他們的調(diào)用關(guān)系可以參考這張圖:

分析
0x01
public Handler(Callback callback, boolean async) {
// 代碼省略
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
從 Handler 默認(rèn)的構(gòu)造函數(shù)我們可以看到,Handler 內(nèi)部會(huì)通過 Looper.myLooper() 來獲取 Looper 對(duì)象,從而與之關(guān)聯(lián)。
0x02
我們之前已經(jīng)知道 Looper 管理著消息隊(duì)列,從這里深入進(jìn)去看看是如何跟 MessageQueue 建立聯(lián)系。
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
在 Looper.myLooper() 里我們看到,Looper 是通過 sThreadLocal.get() 來獲取,那么我們又是何時(shí)將 Looper 設(shè)置給 sThreadLocal 的呢?答案就在 prepare() 方法里。
我們看到 sThreadLocal.set(new Looper(quitAllowed)); 實(shí)例化了一個(gè) Looper 對(duì)象給 sThreadLocal 并且一個(gè)線程只有一個(gè) Looper 。
同時(shí)我也貼出了 prepareMainLooper() 方法,根據(jù)名字大家都可以猜到,這個(gè)方法就是在 Android 主線程(UI)線程調(diào)用的方法,而在這個(gè)方法里也調(diào)用了 prepare(false) 我們看到這里傳入的是 false ,表明主線程這里的 Looper 是無法執(zhí)行 quit() 方法。
我在這里貼出 ActivityThread 的 Main() 方法的部分代碼,這也是我們程序的入口:
public static void main(String[] args) {
// 代碼省略
Looper.prepareMainLooper(); // 創(chuàng)建消息循環(huán) Looper
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler(); // UI 線程的 Handler
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop(); // 執(zhí)行消息循環(huán)
}
在這里我們更清楚了為什么可以直接在主線程創(chuàng)建 Handler ,而不會(huì)發(fā)生異常。
以上,我們明白了 Looper 是通過 prepare() 方法與線程建立聯(lián)系,同時(shí)不同線程是無法訪問對(duì)方的消息隊(duì)列。
為什么 Handler 要在主線程創(chuàng)建才能更新 UI 呢?
因?yàn)?Handler 要與主線程的消息隊(duì)列關(guān)聯(lián)上,這樣 handleMessage() 才會(huì)執(zhí)行在 UI 線程。
0x03
Looper 的核心其實(shí)是它循環(huán)取出消息的代碼:
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// 死循環(huán)
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
/// Handler msg.target
msg.target.dispatchMessage(msg); // 派發(fā)消息
// 代碼省略
msg.recycleUnchecked();
}
}
從上面代碼我們可以看到,Looper 在 loop() 方法里建立了一個(gè)死循環(huán),通過消息隊(duì)列里不斷的取出消息,交給 Handler 去處理。
這個(gè)時(shí)候你可能會(huì)有一個(gè)問題:
Android 中為什么主線程不會(huì)因?yàn)?Looper.loop() 里的死循環(huán)卡死?
我比較推薦 Gityuan 的回答
回到我們這里,在循環(huán)中是通過 msg.target.dispatchMessage(msg); 派發(fā)消息。其中 msg 是 Message 類型,簡(jiǎn)單看看它的成員:
public final class Message implements Parcelable {
Handler target;
Runnable callback;
Message next;
public Object obj;
public int arg1;
public int arg2;
// 代碼省略
}
可以知道消息隊(duì)列是鏈表實(shí)現(xiàn)的,并且 target 是 Handler 類型。
現(xiàn)在就可以連通了,通過 Handler 將 Message 投遞給消息隊(duì)列(鏈表),Looper.loop() 循環(huán)從消息隊(duì)列里取出消息,又將消息分發(fā)給 Handler 去處理。通過這個(gè) target 我們也可以知道一個(gè)小細(xì)節(jié),Handler 只能處理自己所發(fā)出的消息。
0x04
理解清楚之后我們跟著順序,看看 Handler 是如何處理和分發(fā)消息的。
// 處理消息方法,交給子類復(fù)寫
public void handleMessage(Message msg) {
}
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
我們看到 dispatchMessage() 只是一個(gè)分發(fā)方法,如果 Runnable 類型的 callback 為空,則執(zhí)行 handleMessage(msg) 處理信息,該方法為空,是交給子類進(jìn)行復(fù)寫,并且執(zhí)行線程是在 Handler 所創(chuàng)建的線程。
如果 callback 不為空,則會(huì)執(zhí)行 handleCallback(msg) 來處理信息,該方法會(huì)調(diào)用 callback 的 run() 方法。
其實(shí)說簡(jiǎn)單一點(diǎn),就是 Handler 的兩種分發(fā)類型。
一種是 post(r) 另一種是 sendMessage(msg)。
我們具體看看這兩個(gè)方法:
public final boolean post(Runnable r){
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r){
Message m = Message.obtain();
m.callback = r;
return m;
}
public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis){
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this; // 與當(dāng)前 Handler 綁定
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
做了一個(gè)導(dǎo)圖,方便理解下:

從中我們可以看到,在 post(r) 時(shí),會(huì)將 Runnable 包裝成 Message 對(duì)象,并且賦值給 Message 的 callback 字段,最后跟 sendMessage(msg) 方法一樣將消息插入隊(duì)列。
根據(jù)代碼和導(dǎo)圖,無論是 post(r) 還是 sendMessage(msg) 都會(huì)最終調(diào)用 sendMessageAtTime(msg,time)
總結(jié)
Handler 最終將消息追加到 MessageQueue 中,而 Looper 不斷的從 MessageQueue 中讀取消息,并且調(diào)用 Handler 的 dispatchMessage 分發(fā)消息,最后交給上層處理消息。