轉(zhuǎn)載:Android中消息系統(tǒng)模型和Handler Looper

原文鏈接: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 消息處理

大致模型圖如下:

image

消息系統(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è)什么樣的。

image

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)系可以用下面圖來表示:

image

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)用MessageQueueenqueueMessage方法:

  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è)利用的很好很巧妙。

參考文章:http://blog.csdn.net/maxleng/article/details/5552976

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容