Android中訊息系統模型和Handler Looper

來源:互聯網
上載者:User

標籤:

http://www.cnblogs.com/bastard/archive/2012/06/08/2541944.html

      Android中訊息系統模型和Handler Looper

  作為Android中大量使用的Handler,結合Thread使其具有眾多的使用形式和方法,

讓我一時感覺這個東西有些玄乎,不明所以然,這到底是一個什麼樣的存在呢?通過網上

資料和源碼的學習,這個Handler也差不多弄清楚了,現在總結下這個學習結果。

 

一 Handler作用和概念

通過官方文檔瞭解到Handler的大致概念是:

  Handler能夠讓你發送和處理訊息,以及Runnable對象;每個Handler對象對應一個Thread和

Thread的訊息佇列。當你建立一個Handler時,它就和Thread的訊息佇列綁定在一起,然後就可以

傳遞訊息和runnable對象到訊息佇列中,執行訊息後就從訊息佇列中退出。

 

  Handler的作用就是:調度訊息和runnable對象去被執行;使動作在不同的線程中被執行。

  當一個應用程式中進程被建立時,它的主線程專門運行訊息佇列(messageQueue),去管

理頂層的應用程式相關的對象如:activity,broadcastReceiver,windows等,你可以建立你

的Thread,和主線程進行互動——通過Handler,互動的方法就是通過post或者sendMessage。

但是在你的新線程中,給定的Message或者Runnable,會在適當的時候的被調度和處理。

(即不會被立即處理——阻塞式)。

  這是官方文檔中對Handler描述的大致意思(英文比較爛翻譯不定正確)。

 

從這些文檔中我們大概瞭解到handler幹了些什麼:

  •   運行在某個線程上,共用線程的訊息佇列;
  •   接收訊息、調度訊息,派發訊息和處理訊息;
  •   實現訊息的非同步處理;

基本上就是和訊息有關,那麼這實際上是在幹什麼呢?

  ——建立訊息處理模型/系統。

  

  要學習Handler,看到肯定是和訊息有關,可能還是需要先熟悉一下訊息系統的構成和簡單原理。

下面就先學習一下訊息系統的基本原理。

二 訊息系統的基本原理和構成

       從一般的訊息系統模型的建立大致構成以下幾個部分:

    l  訊息原型

    l  訊息佇列

    l  發送訊息

    l  訊息迴圈

    l  訊息擷取

    l  訊息派發

    l  訊息處理

大致模型圖如下:

 

    

 

 

  訊息系統模型一般會包括以上七個部分(訊息原型,訊息佇列,訊息發送,訊息迴圈,訊息擷取,

訊息派發,訊息處理)。實際上的核心是訊息佇列和訊息迴圈,其餘部分都是圍繞這兩部分進行的。

  從前面文檔的分析中我們知道Handler就是用來建立訊息處理的系統模型,那麼和這裡基本訊息

系統模型相比,那麼Handler又是如何囊括這七個部分的呢?

  在Android中對這六個部分進行了抽象成四個獨立的部分:

    Handler,Message,MessageQueue,Looper;

  •   Message就是訊息原型,包含訊息描述和資料,
  •   MessageQueue就是訊息佇列,
  •   Looper完成訊息迴圈
  •   Handler就是駕馭整個訊息系統模型,統領Message,MessgeQueue和Looper;

  

  Handler能夠實現訊息系統模型,那麼具體是如何進行工作的呢,下面探究一下這其中工作的方法和原理。

 

三 Handler工作原理分析

  要瞭解Handler工作原理,先看一下這個系統模型具體組成的階層架構是個什麼樣的。

 

      

 

Looper

  實現Thread的訊息迴圈和訊息派發,預設情況下Thread是沒有這個訊息迴圈的既沒有Looper;

需要主動去建立,然後啟動Looper的訊息迴圈loop;與外部的互動通過Handler進行;

MessageQueue

  訊息佇列,由Looper所持有,但是訊息的添加是通過Handler進行;

  

  訊息迴圈和訊息佇列都是屬於Thread,而Handler本身並不具有Looper和MessageQueue;

但是訊息系統的建立和互動,是Thread將Looper和MessageQueue交給某個Handler維護建立訊息系統模型。

  所以訊息系統模型的核心就是Looper。訊息迴圈和訊息佇列都是由Looper建立的,

而建立Handler的關鍵就是這個Looper。

  一個Thread同時可以對應多個Handler,一個Handler同時只能屬於一個Thread。Handler屬於哪個

Thread取決於Handler在那個Thread中建立。

  在一個Thread中Looper也是唯一的,一個Thread對應一個Looper,建立Handler的Looper來自哪個Thread,

Handler屬於哪個Thread。

  故建立Thread訊息系統,就是將Thread的Looper交給Handler去打理,實現訊息系統模型,完成訊息的非同步處理。

  

Handler與Thread及Looper的關係可以用下面圖來表示:

    

 

       Handler並不等於Thread,必須通過Thread的Looper及其MessageQueue,

用來實現Thread訊息系統模型,依附於Thread上。

 

線上程建立Handler時:

  使Handler滿足訊息系統需要的條件,將Thread中的Looper和MessageQueue交給Handler來負責維護。

線上程中建立Handler,需要做以下工作:

  l  擷取Thread中的Looper交給Handler的成員變數引用維護;

  l  通過Looper擷取MessageQueue交給Handler的成員變數引用維護。

 

  那麼訊息系統模型建立完成之後,按照訊息系統運行,

從Handler來看就是發送訊息派發訊息,與此線程訊息系統的互動都由Handler完成。

訊息發送和派發介面:

  l  post(runnable)訊息,Runnable是訊息回調,經過訊息迴圈引發訊息回呼函數執行;

  l  sendMessage(Message)訊息,經過訊息迴圈派發訊息處理函數中處理訊息;

  l  dispatchMessage       派發訊息,若是post或帶有回呼函數則執行回呼函數,否則執行

      訊息處理函數Handler的handleMessage(通常衍生類別重寫)。

 

  以上就是Handler如何?Thread訊息系統模型的大致介紹。

下面將具體分析是如何?訊息系統模型啟動並執行。

 

四 Handler實現流程分析

  我們知道Handler就是一個訊息系統的外殼,屬於某個Thread並封裝了Thread的Looper

及其MessageQueue;與外部進行互動(同一個線程內或者線程之間),接收派發和處理訊息,

訊息系統模型的核心是Looper。

  下面看看Handler是如何建立跑起來的,以msg訊息為例,runnable實質是一樣。

1 Handler的建立 

  Handler唯一屬於某個Thread,在某個Thread中建立Handler時,需要擷取Thread的Looper

及其MessageQueue,建立Handler關鍵是Looper的來源。

 

  Handler提供了好幾個建構函式但其本質一致:

由外部傳入Looper:當前線程或其他線程    

  public Handler(Looper looper) {
        //初始化構建訊息系統參數 mLooper = looper; mQueue = looper.mQueue; mCallback = null;  }

從當前線程擷取:由建立Handler的Thread決定

       

  public Handler() {
        //初始化構建訊息系統參數 mLooper = Looper.myLooper(); mQueue = mLooper.mQueue; mCallback = null;  }  public static Looper myLooper() { return sThreadLocal.get(); }

 

  不管哪種方式,我們知道Thread在預設情況下是沒有建立訊息迴圈Looper執行個體的。

要實現訊息迴圈必須確保Thread的Looper建立。如何確保呢?

  Looper提供了靜態函數:

public static void prepare() {     if (sThreadLocal.get() != null) {              throw new RuntimeException("Only one Looper may be created per thread");     }     sThreadLocal.set(new Looper());}//儲存線程的局部變數static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

看到這裡剛開始讓我很是奇怪和迷惑:

  Looper一個獨立的類,又不屬於某個Thread,而這裡建立Looper的函數又是靜態,

屬於整個Looper類;建立Looper之後交給靜態成員變數sThreadLocal儲存,擷取

sThreadLocal.get(),那麼一個靜態變數屬於整個類,屬性更改始終有效。一次建立之後

sThreadLocal.get()永遠都不等於null!

  

  而Thread和Looper是唯一對應的,那這裡豈不是所有的Thread都是用同一個Looper,不可能!

所以肯定這個ThreadLocal是有玄機的。網上一查:

  ThreadLocal:

    維護線程的變數,為每個使用該變數的線程執行個體提供獨立的變數副本,每個線程都能夠獨立使用該變數,

    而互不影響。(詳細可參考:http://blog.csdn.net/qjyong/article/details/2158097)

  所以每一個線程調用Looper.prepare時,都會建立為其唯一的Looper。

 

  要建立Handler,需要先建立線程的Looper,才能建立訊息系統模型。通過Looper我們建立了

Thread上的訊息系統模型Handler,可以來進行訊息系統的一系列流程了。

 

2 訊息發送 

訊息發送兩種方式:post和sendMessage;

       post針對runnable對象;Runnable是一個介面,就是一個回呼函數(提供了run方法)

       sendMessage針對Message對象;

       

       下面通過代碼具體看一下這個過程:

public final boolean post(Runnable r){       return  sendMessageDelayed(getPostMessage(r), 0);}public final boolean sendMessage(Message msg){    return sendMessageDelayed(msg, 0);}

 

  看到post和sendMessage發送訊息時,僅僅是對象不同而已,Runnable和Message;

但實際上都是Message的形式來描述。

 

這跟我通常理解的訊息機制不同:

  通常post訊息是將訊息加入到訊息佇列中並不立即執行就返回,send訊息是立即執行等待訊息執行完才返回。

  而這裡post或者send都是將訊息放入到訊息佇列中,然後立即返回,等待訊息迴圈時擷取訊息被執行。

 

  這裡提供了眾多的訊息發送方法來指定訊息的執行時間和順序,具體可以查看原始碼。

訊息執行順序是根據訊息佇列中訊息的排列順序而定。

  下面看一下發送訊息後將訊息加入到訊息佇列中的代碼:

Handler調用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; } ……  }

  

  可以看到是按照時間順序將訊息加入到MessageQueue中;

現在將訊息加入到訊息佇列中儲存起來,訊息並未得到處理,下一步必然是如何派發訊息和處理訊息。

 

3 訊息派發 

建立Thread訊息迴圈由Looper完成,存在一個訊息調度死迴圈:    

  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;                     }                     //派發訊息 到target(Handler)            msg.target.dispatchMessage(msg);            //回收Msg到msgPool                     msg.recycle();              }       }  }

  

  這裡看到訊息派發是由Message的target完成,這個target是什麼呢?是一個Handler。

訊息系統是通過Handler用來與外部互動,把訊息派發出去。可以看到沒有這個Handler,訊息迴圈將結束。

 

訊息派發由Looper通過Handler完成:

  public void dispatchMessage(Message msg) {       //首先判斷runnable對象       if (msg.callback != null) {              handleCallback(msg);       }       else {              //整個訊息系統的回呼函數 可以不用實現自己Handler              if (mCallback != null) {                     if (mCallback.handleMessage(msg)) {                            return;                     }              }
//訊息處理 通常交給Handler衍生類別 handleMessage(msg); }  }

 

  通過訊息派發,這樣就實現訊息的非同步處理。

 

4 訊息原型 

前面看到訊息發送有兩種方式:

  post(Runnable對象),sendMessage(Message對象),而中間都是通過Message對象

儲存在MessageQueue中。然後訊息派發時處理方式不同。如果在sendMessage時將將訊息對象

附上Runnable對象,則post和sendMessage沒有區別了。所以這兩種方式很好理解基本一致,處理的方式不同罷了。

  

  訊息系統模型中,我們的真正的訊息原型是什麼,都具有那些功能,下面看一下Message中到底

包含了那些東西,能有效協助我們合理的運用訊息系統來完成一些任務和處理。

Message訊息原型:

  public final class Message implements Parcelable {         //標識訊息         public int what;         int flags;         long when;               //傳遞簡單資料         public int arg1;         public int arg2;             //傳遞較複雜資料 對象         public Object obj;         Bundle data;         //處理訊息的目標Handler         Handler target;            //訊息派發時 執行的Runnable對象         Runnable callback;           //使訊息形成鏈表         Message next;         //建立一個訊息pool,回收msg,以避免重複建立節約開銷         private static Message sPool;         private static int sPoolSize = 0;         private static final int MAX_POOL_SIZE = 10;  }  

  

  看到提供了很豐富的屬性來描述訊息,針對具體問題選擇使用那些屬性去怎麼樣描述訊息了。

  擷取新的Message對象時,Message提供了obtain方法:避免我們自己去分配Message新的對象,

通過obtain擷取,可能從MessagePool中擷取,節約開銷。

 

下面看一下這個MessagePool是如何建立的:

  通常訊息處理完畢的時候,訊息也基本上處於無用狀態可以釋放回收了。對於需要頻繁的建立釋放的對象來說,

建立和釋放類執行個體都是要開銷的,太頻繁的使開銷增大不好,像Message這種很有可能會頻繁的建立。

 

  於是我們可以將建立的對象用完之後儲存在一個Pool裡面,以便再重複利用節約頻繁建立釋放開銷。

是如何建立的呢?必然是在訊息處理完畢之後才能進行。

MessagePool建立:

public static void loop() {       while (true) {              //派發訊息              msg.target.dispatchMessage(msg);              //訊息處理完畢 回收        msg.recycle();    }}     public void recycle() {       //回收Message 建立全域的MessagePool       if (sPoolSize < MAX_POOL_SIZE) {           next = sPool;           sPool = this;           sPoolSize++;       }}

 

五 Handler的應用

  以上這就是整個Handler作用及訊息系統模型的建立。

使用也非常簡單,雖然有很多方式,但只要理解Handler是建立在Looper上,實現Thread的

訊息系統處理模型,實現訊息非同步處理,我想對與Handler基本應用上沒有什麼不能理解的了。

其他方面可以去看源碼了。

  Handler使用起來是非常簡單的,關鍵就是如何利用訊息的非同步處理,來合理的完成我們

需要功能和任務。對於一個Thread,我們使用好幾個Handler來進行非同步處理,也可以建立新的Thread,

通過Handler來實現訊息非同步處理等等,應用情境很多如何用的好用的合理,這就沒什麼經驗了。

  至於如何使用,源碼中很多例子可以看一下AsyncQueryHandler這個類,其中兩個線程,

完成查詢工作,通過Handler進行線程之間有訊息傳遞。感覺這個利用的很好很巧妙。

 

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

Android中訊息系統模型和Handler Looper

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.