Handler在Android中負責(zé)調(diào)度消息并將來某個時段處理消息。Android有大量的消息驅(qū)動方式來進行交互,比如四大組件的的啟動過程的交互,都離不開消息機制。
消息機制涉及MessageQueue/Message/Looper/Handler這4個類。
Message:消息分為硬件產(chǎn)生的消息(如按鈕、觸摸)和軟件生成的消息;
MessageQueue:消息隊列的主要功能向消息池投遞消息和取走消息池的消息;
Handler:消息輔助類,主要功能向消息池發(fā)送各種消息事件(Handler.sendMessage)和處理相應(yīng)消息事件(Handler.handleMessage);
Looper:不斷循環(huán)執(zhí)行(Looper.loop),按分發(fā)機制將消息分發(fā)給目標(biāo)處理者。
梳理過程從handler構(gòu)造函數(shù)開始,然后產(chǎn)生一條消息通過sendMessage向下分發(fā)。之后又是如何被調(diào)度,最后被怎樣處理。
public Handler(@Nullable 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;
}
這里是通過Looper中的myLooper方法來獲得Looper實例的,如果Looper為null的話就會拋異常,拋出的異常內(nèi)容翻譯過來就是無法在未調(diào)用 Looper.prepare()的線程內(nèi)創(chuàng)建handler,new handler的時候沒有報錯那么就一定之前就調(diào)用了 Looper.Prepare(),在哪里創(chuàng)建的呢?
答案在 ActivityThread.main() 中。
ActivityThread 的 main()方法就是整個APP的入口,也就是我們通常所講的主線程, UI線程。但他實際上并不是一個線程,ActivityThread 并沒有繼承 Thread 類,我們可以把他理解為主線程的管理者,負責(zé)管理主線程的執(zhí)行,調(diào)度等操作,看下main方法的源碼。
public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
Looper.loop();
...
}
兩個關(guān)鍵方法 Looper.prepareMainLooper()和Looper.loop(),loop方法后面再分析,繼續(xù)看prepareMainLooper的方法內(nèi)部如下:
// 1
public static void prepareMainLooper() {
// 2
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
// 2
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// 3
sThreadLocal.set(new Looper(quitAllowed));
}
// 3
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
到1??這里就解決了,為什么我們在主線程中使用Handler之前沒有調(diào)用Looper.prepare方法的問題了,就是在這里調(diào)用了prepare 方法。
2??prepare方法內(nèi)部把 Looper 放到ThreadLocal中與當(dāng)前線程綁定,保證一個線程只有一個Looper實例,同時一個Looper實例也只有一個MessageQueue。
3??在Looper的構(gòu)造函數(shù)中始化MessageQueue
所以初始化Handler之前Looper 和 MessageQueue就已經(jīng)初始化了,并把Looper放到ThreadLocal中。ThreadLocal有個特點是你set進去的值是以當(dāng)前所處的線程為key,value就是你set的值。源碼如下:
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
Handler的sendMessage方法都做了什么
先看一下sendMessage的流程圖:

簡單過一遍,sendXXX 這些方式最終還是會調(diào)用到 enqueueMessage 這個方法上來的邏輯最后調(diào)用queue.enqueueMessage 添加消息到消息隊列MessageQueue中,下面就是消息的入隊邏輯
boolean enqueueMessage(Message msg, long when) {
msg.when = when;
Message p = mMessages;
boolean needWake;
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 {
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
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;
}
}
return true;
}
消息入隊順序是按照 Message 觸發(fā)時間 long when入隊的,有新消息加入時,會循環(huán)遍歷當(dāng)前消息隊列,對比消息觸發(fā)時間,直到找到當(dāng)前消息合適的插入位置,以此來保證所有消息的觸發(fā)時間順序。即 MessageQueue 添加消息到消息隊列中。
所以消息的存儲與管理MessageQueue 來負責(zé)
誰負責(zé)把消息分發(fā)出去
Handler把Message交給MessageQueue并存儲起來 ,那么誰來負責(zé)把我這里的消息分發(fā)出去并且告訴主線程的人(Handler)呢?答案就是 Looper 了!

之前分析的ActivityThread.main()中的Looper.loop還沒有講到我們接著跟進去看一下源碼
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
for (;;) {
// 循環(huán)調(diào)用 MessageQueue 的 next 方法獲取消息
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
try {
msg.target.dispatchMessage(msg);
}
}
}
loop()不斷從MessageQueue中取消息,把消息交給target(handler)的dispatchMessage方法處理。下面是dispatchMessage
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
可以看到dispatchMessage最后調(diào)用了handleMessage方法,在源碼里面是個空實現(xiàn)。需要我們在創(chuàng)建handler的時候復(fù)寫,根據(jù)不同的message處理不同的業(yè)務(wù)邏輯。
整個Handler的消息分發(fā)調(diào)度流程就講完了,為了增強記憶,我再把整個流程拼成一塊如下圖:
