要想深入理解Handler機制,就要理解:
- Android為何要引入Handler機制?
- Handler機制究竟是什么?
如果去查閱官方Handler文檔,會發(fā)現(xiàn)官方?jīng)]有給Handler下過定義,更沒有介紹為何要引入Handler機制。官方文檔的第一句就說Handler允許你發(fā)送和處理與一個線程的消息隊列關(guān)聯(lián)的消息和任務(wù)。這是對Handler能力和用法的一種描述,并沒有講為什么和是什么,這就造成初學(xué)者只知道怎么用Handler,但是不知道其背后的設(shè)計思想和原理。
Android為何引入Handler
要知道Android為何引入Handler機制,首先要了解Java線程機制:
- 線程執(zhí)行任務(wù)
- 任務(wù)在線程的run方法中執(zhí)行
- run方法結(jié)束,線程終止
這種機制的問題在于,創(chuàng)建線程的開銷非常大,即使通過線程池重用線程,線程調(diào)度的開銷對于數(shù)量多、密度大、要求快速響應(yīng)的UI更新任務(wù)來說也是不可接受的,于是Android引入Handler線程解決這個問題。Handler線程就是Handler機制的核心:Handler線程永不退出,在run方法中輪詢?nèi)蝿?wù),有任務(wù)就處理,沒任務(wù)就等待。
有些Handler線程是允許退出的。
Android應(yīng)用的主線程是一個不允許退出、生命周期與進程一樣長的線程。
Handler機制工作原理
Handler機制是一整套任務(wù)處理機制,需要Handler、Looper、Message和MessageQueue配合。
- Looper在線程中死循環(huán),使線程不退出
- Handler發(fā)送和處理Message
- Message包含任務(wù)或者執(zhí)行任務(wù)所需的數(shù)據(jù)
- Message發(fā)送給MessageQueue,MessageQueue負責(zé)Message的排序與出隊
Message是Android中的一個重要概念,它把Android應(yīng)用從Java的任務(wù)處理系統(tǒng)變成了消息處理系統(tǒng)。

Looper
要把一個線程變成Handler線程,只需在線程的run方法中調(diào)用Looper.prepare()和Looper.loop()。
class LooperThread extends Thread {
public void run() {
Looper.prepare();
Looper.loop();
}
}
Looper的創(chuàng)建非常巧妙,是在Looper.prepare()中完成的。Looper實例存儲在ThreadLocal中,可以通過Looper.myLooper()獲取。Looper默認是可以退出的,要創(chuàng)建不可退出的Looper,需要調(diào)用Looper.prepare(false),主線程Looper正是這樣創(chuàng)建的。要注意的是,一個線程只能與一個Looper關(guān)聯(lián)。
Looper創(chuàng)建后通過Looper.loop()完成工作。正如上文所說,Looper.loop()在Thread.run方法中輪詢消息,使線程不退出、消息串行處理。
// Looper.java
public static void loop() {
for (;;) {
Message msg = queue.next(); // might block
msg.target.dispatchMessage(msg);
}
}
MessageQueue
MessageQueue是在Looper的構(gòu)造函數(shù)內(nèi)創(chuàng)建的。由此可知,線程、Looper和MessageQueue三者是一一對應(yīng)的。
MessageQueue的主要工作是處理Message入列和安排Message出列。MessageQueue并不是常規(guī)的先進先出隊列,而是根據(jù)Message期望執(zhí)行的時間排列的。
- 入列:boolean enqueueMessage(Message msg, long when)
- 出列:Message next()
這兩個方法都有用到native代碼,實現(xiàn)比較復(fù)雜,就不分析了(因為沒看懂??)。
Message
Message是一個數(shù)據(jù)類,攜帶要執(zhí)行的任務(wù)(Runnable)或執(zhí)行任務(wù)所需的數(shù)據(jù)(what、arg1、arg2、obj、data)以及任務(wù)處理者(Handler)和任務(wù)執(zhí)行時間(when)。Message的實現(xiàn)是一個單鏈表結(jié)點,因此可以攜帶下一條Message。MessageQueue正是基于Message單鏈表實現(xiàn)的。
由于是數(shù)據(jù)類,且應(yīng)用中需要大量Message,因此Message實現(xiàn)了重用緩存池,通過Message.obtain()獲取。與MessageQueue一樣,Message緩存池也是基于其單鏈表實現(xiàn)的,不同的是緩存池是棧而非隊列。
Handler
官方文檔說,Handler與創(chuàng)建它的線程及該線程的MessageQueue關(guān)聯(lián)(When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it)。這說的是不指定Looper的情況下,Handler自動與該線程的Looper關(guān)聯(lián),上文說,線程、Looper和MessageQueue三者一一對應(yīng),因此默認情況下,Handler與創(chuàng)建它的線程及該線程的MessageQueue關(guān)聯(lián)。但在創(chuàng)建Handler時是可以指定Looper的,這樣就會與Looper所在的線程和MessageQueue關(guān)聯(lián)。
不管Handler在哪個線程創(chuàng)建,它發(fā)出的消息都是在與之關(guān)聯(lián)的Looper所在的線程處理的,這正是Handler用于線程間通信的原理。由于后臺線程不允許更新UI,因此后臺線程通過一個與主線程Looper關(guān)聯(lián)的Handler(new Handler(Looper.getMainLooper()))來更新UI。
Handler發(fā)送消息有兩種方式:
- sendMessage(Message)
- post(Runnable)
但其實就一種,因為Runnable也會轉(zhuǎn)為Message。Handler發(fā)送消息還可以設(shè)置延時或定時,但最終也是一種,因為延時也會被轉(zhuǎn)為定時任務(wù)。因此所有的發(fā)送方式最終都調(diào)用下列方法處理:
// Handler.java
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
放入MessageQueue中的Message會被逐個取出,串行處理。有3處對象可以處理消息:
- Message自身callback(一般是post(Runnable)方式發(fā)送的消息)
- Handler創(chuàng)建時設(shè)置的mCallback
- Handler
// Handler.java
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
HandlerThread
Android應(yīng)用的大部分消息都可以由主線程處理,如果需要在后臺線程中處理消息,可以創(chuàng)建一個新的Handler線程。
開發(fā)者并不需要自己實現(xiàn)Handler線程,直接使用內(nèi)置的HandlerThread即可:
HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
源碼篇和實現(xiàn)篇
要想深入理解Handler機制,光憑一篇引路文章是不夠的,更重要的是閱讀源碼、動手實踐和總結(jié)分享。
是不是很期待源碼篇和實踐篇?你來寫!
看好你哦~