原文鏈接:https://www.cnblogs.com/bastard/archive/2012/06/08/2541944.html
Android中消息系統(tǒng)模型和Handler Looper
作為Android中大量使用的Handler,結(jié)合Thread使其具有眾多的使用形式和方法,
讓我一時(shí)感覺這個(gè)東西有些玄乎,不明所以然,這到底是一個(gè)什么樣的存在呢?通過網(wǎng)上
資料和源碼的學(xué)習(xí),這個(gè)Handler也差不多弄清楚了,現(xiàn)在總結(jié)下這個(gè)學(xué)習(xí)結(jié)果。
一 Handler作用和概念
通過官方文檔了解到****Handler****的大致概念是:
Handler能夠讓你發(fā)送和處理消息,以及Runnable對象;每個(gè)Handler對象對應(yīng)一個(gè)Thread和
Thread的消息隊(duì)列。當(dāng)你創(chuàng)建一個(gè)Handler時(shí),它就和Thread的消息隊(duì)列綁定在一起,然后就可以
傳遞消息和runnable對象到消息隊(duì)列中,執(zhí)行消息后就從消息隊(duì)列中退出。
Handler的作用就是:調(diào)度消息和runnable對象去被執(zhí)行;使動(dòng)作在不同的線程中被執(zhí)行。
當(dāng)一個(gè)應(yīng)用程序中進(jìn)程被創(chuàng)建時(shí),它的主線程專門運(yùn)行消息隊(duì)列(messageQueue),去管
理頂層的應(yīng)用程序相關(guān)的對象如:activity,broadcastReceiver,windows等,你可以創(chuàng)建你
的Thread,和主線程進(jìn)行交互——通過Handler,交互的方法就是通過post或者sendMessage。
但是在你的新線程中,給定的Message或者Runnable,會(huì)在適當(dāng)?shù)臅r(shí)候的被調(diào)度和處理。
(即不會(huì)被立即處理——阻塞式)。
這是官方文檔中對Handler描述的大致意思(英文比較爛翻譯不定正確)。
從這些文檔中我們大概了解到handler干了些什么:
- 運(yùn)行在某個(gè)線程上,共享線程的消息隊(duì)列;
- 接收消息、調(diào)度消息,派發(fā)消息和處理消息;
- 實(shí)現(xiàn)消息的異步處理;
基本上就是和消息有關(guān),那么這實(shí)際上是在干什么呢?
——建立消息處理模型/系統(tǒng)。
要學(xué)習(xí)Handler,看到肯定是和消息有關(guān),可能還是需要先熟悉一下消息系統(tǒng)的構(gòu)成和簡單原理。
下面就先學(xué)習(xí)一下消息系統(tǒng)的基本原理。
二 消息系統(tǒng)的基本原理和構(gòu)成
從一般的消息系統(tǒng)模型的建立大致構(gòu)成以下幾個(gè)部分:
| 消息原型
l 消息隊(duì)列
l 發(fā)送消息
l 消息循環(huán)
l 消息獲取
l 消息派發(fā)
l 消息處理
大致模型圖如下:

消息系統(tǒng)模型一般會(huì)包括以上七個(gè)部分(消息原型,消息隊(duì)列,消息發(fā)送,消息循環(huán),消息獲取,
消息派發(fā),消息處理)。實(shí)際上的核心是消息隊(duì)列和消息循環(huán),其余部分都是圍繞這兩部分進(jìn)行的。
從前面文檔的分析中我們知道Handler就是用來建立消息處理的系統(tǒng)模型,那么和這里基本消息
系統(tǒng)模型相比,那么Handler又是如何囊括這七個(gè)部分的呢?
在Android中對這六個(gè)部分進(jìn)行了抽象成四個(gè)獨(dú)立的部分:
Handler,Message,MessageQueue,Looper;
- Message就是消息原型,包含消息描述和數(shù)據(jù),
- MessageQueue就是消息隊(duì)列,
- Looper完成消息循環(huán)
- Handler就是駕馭整個(gè)消息系統(tǒng)模型,統(tǒng)領(lǐng)Message,MessgeQueue和Looper;
Handler能夠?qū)崿F(xiàn)消息系統(tǒng)模型,那么具體是如何進(jìn)行工作的呢,下面探究一下這其中工作的方法和原理。
三 Handler工作原理分析
要了解Handler工作原理,先看一下這個(gè)系統(tǒng)模型具體組成的層次結(jié)構(gòu)框架是個(gè)什么樣的。

Looper:
實(shí)現(xiàn)Thread的消息循環(huán)和消息派發(fā),缺省情況下Thread是沒有這個(gè)消息循環(huán)的既沒有Looper;
需要主動(dòng)去創(chuàng)建,然后啟動(dòng)Looper的消息循環(huán)loop;與外部的交互通過Handler進(jìn)行;
MessageQueue:
消息隊(duì)列,由Looper所持有,但是消息的添加是通過Handler進(jìn)行;
消息循環(huán)和消息隊(duì)列都是屬于Thread,而Handler本身并不具有Looper和MessageQueue;
但是消息系統(tǒng)的建立和交互,是Thread將Looper和MessageQueue交給某個(gè)Handler維護(hù)建立消息系統(tǒng)模型。
所以消息系統(tǒng)模型的核心就是Looper。消息循環(huán)和消息隊(duì)列都是由Looper建立的,
而建立Handler的關(guān)鍵就是這個(gè)Looper。
一個(gè)Thread同時(shí)可以對應(yīng)多個(gè)Handler,一個(gè)Handler同時(shí)只能屬于一個(gè)Thread。Handler屬于哪個(gè)
Thread取決于Handler在那個(gè)Thread中建立。
在一個(gè)Thread中Looper也是唯一的,一個(gè)Thread對應(yīng)一個(gè)Looper,建立Handler的Looper來自哪個(gè)Thread,
Handler屬于哪個(gè)Thread。
故建立Thread消息系統(tǒng),就是將Thread的Looper交給Handler去打理,實(shí)現(xiàn)消息系統(tǒng)模型,完成消息的異步處理。
Handler與Thread及Looper的關(guān)系可以用下面圖來表示:

Handler并不等于Thread,必須通過Thread的Looper及其MessageQueue,用來實(shí)現(xiàn)Thread消息系統(tǒng)模型,依附于Thread上。
在線程建立Handler時(shí):
使Handler滿足消息系統(tǒng)需要的條件,將Thread中的Looper和MessageQueue交給Handler來負(fù)責(zé)維護(hù)。
在線程中建立Handler,需要做以下工作:
l 獲取Thread中的Looper交給Handler的成員變量引用維護(hù);
l 通過Looper獲取MessageQueue交給Handler的成員變量引用維護(hù)。
那么消息系統(tǒng)模型建立完成之后,按照消息系統(tǒng)運(yùn)行,
從Handler來看就是發(fā)送消息派發(fā)消息,與此線程消息系統(tǒng)的交互都由Handler完成。
消息發(fā)送和派發(fā)接口:
l post(runnable)消息,Runnable是消息回調(diào),經(jīng)過消息循環(huán)引發(fā)消息回調(diào)函數(shù)執(zhí)行;
l sendMessage(Message)消息,經(jīng)過消息循環(huán)派發(fā)消息處理函數(shù)中處理消息;
l dispatchMessage 派發(fā)消息,若是post或帶有回調(diào)函數(shù)則執(zhí)行回調(diào)函數(shù),否則執(zhí)行
消息處理函數(shù)Handler的handleMessage(通常派生類重寫)。
以上就是Handler如何實(shí)現(xiàn)Thread消息系統(tǒng)模型的大致介紹。
下面將具體分析是如何實(shí)現(xiàn)消息系統(tǒng)模型運(yùn)行的。
四 Handler實(shí)現(xiàn)流程分析
我們知道Handler就是一個(gè)消息系統(tǒng)的外殼,屬于某個(gè)Thread并包裝了Thread的Looper
及其MessageQueue;與外部進(jìn)行交互(同一個(gè)線程內(nèi)或者線程之間),接收派發(fā)和處理消息,
消息系統(tǒng)模型的核心是Looper。
下面看看Handler是如何建立跑起來的,以msg消息為例,runnable實(shí)質(zhì)是一樣。
1 Handler的建立
Handler唯一屬于某個(gè)Thread,在某個(gè)Thread中建立Handler時(shí),需要獲取Thread的Looper
及其MessageQueue,建立Handler關(guān)鍵是Looper的來源。
Handler提供了好幾個(gè)構(gòu)造函數(shù)但其本質(zhì)一致:
由外部傳入Looper:當(dāng)前線程或其他線程
public Handler(Looper looper) {
//初始化構(gòu)建消息系統(tǒng)參數(shù)
mLooper** = looper;
mQueue** = looper.mQueue;
mCallback** = null;
}
從當(dāng)前線程獲?。?/strong>由創(chuàng)建Handler的Thread決定
public Handler() {
//初始化構(gòu)建消息系統(tǒng)參數(shù)
mLooper = Looper.**myLooper**();
mQueue = mLooper.mQueue;
mCallback = null;
}
public static Looper myLooper() { return sThreadLocal.get();
}
不管哪種方式,我們知道Thread在默認(rèn)情況下是沒有建立消息循環(huán)Looper實(shí)例的。
要實(shí)現(xiàn)消息循環(huán)必須確保Thread的Looper建立。如何確保呢?
Looper提供了靜態(tài)函數(shù):
public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
//存儲(chǔ)線程的局部變量
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
看到這里剛開始讓我很是奇怪和迷惑:
Looper一個(gè)獨(dú)立的類,又不屬于某個(gè)Thread,而這里創(chuàng)建Looper的函數(shù)又是靜態(tài)的,
屬于整個(gè)Looper類;創(chuàng)建Looper之后交給靜態(tài)成員變量sThreadLocal保存,獲取
sThreadLocal.get(),那么一個(gè)靜態(tài)變量屬于整個(gè)類,屬性更改始終有效。一次創(chuàng)建之后
sThreadLocal.get()永遠(yuǎn)都不等于null!
而Thread和Looper是唯一對應(yīng)的,那這里豈不是所有的Thread都是用同一個(gè)Looper,不可能!
所以肯定這個(gè)ThreadLocal是有玄機(jī)的。網(wǎng)上一查:
ThreadLocal:
維護(hù)線程的變量,為每個(gè)使用該變量的線程實(shí)例提供獨(dú)立的變量副本,每個(gè)線程都能夠獨(dú)立使用該變量,
而互不影響。(詳細(xì)可參考:http://blog.csdn.net/qjyong/article/details/2158097)
所以每一個(gè)線程調(diào)用Looper.prepare時(shí),都會(huì)創(chuàng)建為其唯一的Looper。
要建立Handler,需要先創(chuàng)建線程的Looper,才能建立消息系統(tǒng)模型。通過Looper我們建立了
Thread上的消息系統(tǒng)模型Handler,可以來進(jìn)行消息系統(tǒng)的一系列流程了。
2 消息發(fā)送
消息發(fā)送兩種方式:post和sendMessage;
post:針對runnable對象;Runnable是一個(gè)接口,就是一個(gè)回調(diào)函數(shù)(提供了run方法)
sendMessage:針對Message對象;
下面通過代碼具體看一下這個(gè)過程:
public final boolean post(Runnable r){ return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean sendMessage(Message msg){ return sendMessageDelayed(msg, 0);
}
看到post和sendMessage發(fā)送消息時(shí),僅僅是對象不同而已,Runnable和Message;
但實(shí)際上都是Message的形式來描述。
這跟我通常理解的消息機(jī)制不同:
通常post消息是將消息加入到消息隊(duì)列中并不立即執(zhí)行就返回,send消息是立即執(zhí)行等待消息執(zhí)行完才返回。
而這里post或者send都是將消息放入到消息隊(duì)列中,然后立即返回,等待消息循環(huán)時(shí)獲取消息被執(zhí)行。
這里提供了眾多的消息發(fā)送方法來指定消息的執(zhí)行時(shí)間和順序,具體可以查看源代碼。
消息執(zhí)行順序是根據(jù)消息隊(duì)列中消息的排列順序而定。
下面看一下發(fā)送消息后將消息加入到消息隊(duì)列中的代碼:
由Handler調(diào)用MessageQueue的 enqueueMessage方法:
final boolean enqueueMessage (Message msg, long when) {
Message p = mMessages; if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
} else {
Message prev = null; while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
}
……
}
可以看到是按照時(shí)間順序?qū)⑾⒓尤氲組essageQueue中;
現(xiàn)在將消息加入到消息隊(duì)列中存儲(chǔ)起來,消息并未得到處理,下一步必然是如何派發(fā)消息和處理消息。
3 消息派發(fā)
建立Thread消息循環(huán)由Looper完成,存在一個(gè)消息調(diào)度死循環(huán):
public static void loop() {
MessageQueue queue = me.mQueue; while (true) {
Message msg = queue.next(); // might block
if (msg != null) { if (msg.target == null) { // No target is a magic identifier for the quit message.
return;
} //派發(fā)消息 到target(Handler) msg.target.dispatchMessage(msg);//回收Msg到msgPool msg.recycle();
}
}
}
這里看到消息派發(fā)是由Message的target完成,這個(gè)target是什么呢?是一個(gè)Handler。
消息系統(tǒng)是通過Handler用來與外部交互,把消息派發(fā)出去??梢钥吹?jīng)]有這個(gè)Handler,消息循環(huán)將結(jié)束。
消息派發(fā)由****Looper****通過****Handler****完成:
public void dispatchMessage(Message msg) { //首先判斷runnable對象
if (msg.callback != null) {
handleCallback(msg);
} else { //整個(gè)消息系統(tǒng)的回調(diào)函數(shù) 可以不用實(shí)現(xiàn)自己Handler
if (mCallback != null) { if (mCallback.handleMessage(msg)) { return;
}
} //消息處理 通常交給Handler派生類 handleMessage(msg);
}
}
通過消息派發(fā),這樣就實(shí)現(xiàn)消息的異步處理。
4 消息原型
前面看到消息發(fā)送有兩種方式:
post(Runnable對象),sendMessage(Message對象),而中間都是通過Message對象
保存在MessageQueue中。然后消息派發(fā)時(shí)處理方式不同。如果在sendMessage時(shí)將將消息對象
附上Runnable對象,則post和sendMessage沒有區(qū)別了。所以這兩種方式很好理解基本一致,處理的方式不同罷了。
消息系統(tǒng)模型中,我們的真正的消息原型是什么,都具有那些功能,下面看一下Message中到底
包含了那些東西,能有效幫助我們合理的運(yùn)用消息系統(tǒng)來完成一些任務(wù)和處理。
Message消息原型:
public final class Message implements Parcelable {//標(biāo)識消息
public int what;int flags;long when;//傳遞簡單數(shù)據(jù)
public int arg1;public int arg2;//傳遞較復(fù)雜數(shù)據(jù) 對象
public Object obj;
Bundle data;//處理消息的目標(biāo)Handler Handler target;//消息派發(fā)時(shí) 執(zhí)行的Runnable對象 Runnable callback;//使消息形成鏈表 Message next;//建立一個(gè)消息pool,回收msg,以避免重復(fù)創(chuàng)建節(jié)約開銷
private static Message sPool;private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 10;
}
看到提供了很豐富的屬性來描述消息,針對具體問題選擇使用那些屬性去怎么樣描述消息了。
獲取新的Message對象時(shí),Message提供了obtain方法:避免我們自己去分配Message新的對象,
通過obtain獲取,可能從MessagePool中獲取,節(jié)約開銷。
下面看一下這個(gè)MessagePool是如何建立的:
通常消息處理完畢的時(shí)候,消息也基本上處于無用狀態(tài)可以釋放回收了。對于需要頻繁的創(chuàng)建釋放的對象來說,
創(chuàng)建和釋放類實(shí)例都是要開銷的,太頻繁的使開銷增大不好,像Message這種很有可能會(huì)頻繁的創(chuàng)建。
于是我們可以將創(chuàng)建的對象用完之后保存在一個(gè)Pool里面,以便再重復(fù)利用節(jié)約頻繁創(chuàng)建釋放開銷。
是如何建立的呢?必然是在消息處理完畢之后才能進(jìn)行。
MessagePool****建立:
public static void loop() { while (true) { //派發(fā)消息
msg.target.dispatchMessage(msg); //消息處理完畢 回收
msg.recycle();
}
} public void recycle() { //回收Message 建立全局的MessagePool
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
五 Handler的應(yīng)用
以上這就是整個(gè)Handler作用及消息系統(tǒng)模型的建立。
使用也非常簡單,雖然有很多方式,但只要理解Handler是建立在Looper上,實(shí)現(xiàn)Thread的
消息系統(tǒng)處理模型,實(shí)現(xiàn)消息異步處理,我想對與Handler基本應(yīng)用上沒有什么不能理解的了。
其他方面可以去看源碼了。
Handler使用起來是非常簡單的,關(guān)鍵就是如何利用消息的異步處理,來合理的完成我們
需要功能和任務(wù)。對于一個(gè)Thread,我們使用好幾個(gè)Handler來進(jìn)行異步處理,也可以創(chuàng)建新的Thread,
通過Handler來實(shí)現(xiàn)消息異步處理等等,應(yīng)用場景很多如何用的好用的合理,這就沒什么經(jīng)驗(yàn)了。
至于如何使用,源碼中很多例子可以看一下AsyncQueryHandler這個(gè)類,其中兩個(gè)線程,
完成查詢工作,通過Handler進(jìn)行線程之間有消息傳遞。感覺這個(gè)利用的很好很巧妙。