Android開發 之 理解Handler、Looper、MessageQueue、Thread關係

 

本文轉自博客:http://blog.csdn.net/he90227/article/details/43567073

 

 

一. 圖解與概述html

 

首先Android中 的每個線程都會對應一個MessageQueue和Looper。見名知意,MessageQueue即線程用來維護線程產生的消息的消息隊列,而這個 隊列的調度則是由Looper來完成的。Looper負責將產生的消息放入隊列,並及時的將合適的消息從隊列中取出並交由合適的接受者處理。處理消息的便 是每一個線程內部的Handler對象,特別是在UI線程中,因爲Handler與UI處於同一個線程,因此咱們就能夠經過Handler處理接收到的消息 並及時更新UI中的組件。java

 

上述描述便可以實如今其它線程中完成耗時操做並在UI線程中經過Handler更新組件以反映耗時操做的處理效果。android

如下是它們之 間關係的圖示:程序員



理解概念:設計模式

Message:消息,其中包含了消息ID,消息處理對象以及處理的數據等,由MessageQueue統一列隊,終由Handler處理。
Handler:處理者,負責Message的發送及處理。使用Handler時,須要實現handleMessage(Message msg)方法來對特定的Message進行處理,例如更新UI等。
MessageQueue:消息隊列,用來存放Handler發送過來的消息,並按照FIFO規則執行。固然,存放Message並不是實際意義的保存,而是將Message以鏈表的方式串聯起來的,等待Looper的抽取。
Looper:消息泵,不斷地從MessageQueue中抽取Message執行。所以,一個MessageQueue須要一個Looper。
Thread:線程,負責調度整個消息循環,即消息循環的執行場所。
安全

 

簡單關係:多線程


 

Handler,Looper和MessageQueue就是簡單的三角關係。框架

Looper和MessageQueue一一對應,線程和looper也是一一對應,建立一個Looper的 同時,會建立一個MessageQueue。異步

而Handler與它們的關係,只是簡單的彙集關係,即Handler裏會引用當前線程裏的特定Looper 和MessageQueue。
這樣說來,多個Handler均可以共享同一Looper和MessageQueue了。ide

固然,這些Handler也就運行在同一個線程裏。

 

 

消息循環過程:

生成消息

1 Message message = handler.obtainMessage(); 2 message.arg1 = id; 3 message.obj = drawable; 4 handler.sendMessage(message);  

發送消息

 
 1 /**  2  * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>  3  * to this handler.  4  * @param uptimeMillis The absolute time at which the message should be  5  * {@link android.os.SystemClock#uptimeMillis} time-base.  6  * @return Returns true if the message was successfully placed in to the  7  * looper processing the message queue is exiting. Note that a  8  * the looper is quit before the delivery time of the message  9 */ 
public boolean sendMessageAtTime(Message msg, uptimeMillis)
10 { 11 sent = ; 12 MessageQueue queue = mQueue; 13 (queue != ) { 14 msg.target = ; 15 sent = queue.enqueueMessage(msg, uptimeMillis); 16 } 17 { 18 RuntimeException e = RuntimeException( 19 + , e.getMessage(), e); 20 } 21 sent; 22 }

 

 在 Handler.java的sendMessageAtTime(Message msg, long uptimeMillis)方法中,咱們看到,它找到它所引用的MessageQueue,而後將Message的target設定成本身(目的是爲了在 處理消息環節,Message能找到正確的Handler),再將這個Message歸入到消息隊列中。

 

Looper從消息隊列中抽取消息

/** 
 1      public  static final void loop() {  2         Looper me = myLooper();  3         MessageQueue queue = me.mQueue;  4  () {  5             Message msg = queue.next();  6               
 7               
 8               
 9              (msg != ) { 10                  (msg.target == ) { 11                       
12  ; 13  } 14                  (me.mLogging!= ) me.mLogging.println( 15  ); 16  msg.target.dispatchMessage(msg); 17                  (me.mLogging!= ) me.mLogging.println( 18                                             + msg.callback); 19  msg.recycle(); 20  } 21  } 22     }  

 

 在Looper.Java的loop()函數裏,咱們看到,這裏有一個死循環,不斷地從MessageQueue中獲取下一個(next方法)Message,而後經過Message中攜帶的target信息,交由正確的Handler處理(dispatchMessage方法)。

處理

 
 1     /** 
 2  * Handle system messages here.  3      */  
 4     public void dispatchMessage(Message msg) {  5         if (msg.callback != null) {  6  handleCallback(msg);  7         } else {  8             if (mCallback != null) {  9                 if (mCallback.handleMessage(msg)) { 10                     return; 11  } 12  } 13  handleMessage(msg); 14  } 15     }  

 

在 Handler.java的dispatchMessage(Message msg)方法裏,其中的一個分支就是調用handleMessage方法來處理這條Message,而這也正是咱們在職責處描述使用Handler時須要 實現handleMessage(Message msg)的緣由。

至於dispatchMessage方法中的另一個分支,我將會在後面的內容中說明.

 

至此,咱們看到,一個Message經由Handler的發送,MessageQueue的入隊,Looper的抽取,又再一次地回到Handler的懷抱。而繞的這一圈,也正好幫助咱們將同步操做變成了異步操做。

Handler所處的線程及更新UI的方式

在 主線程(UI線程)裏,若是建立Handler時不傳入Looper對象,那麼將直接使用主線程(UI線程)的Looper對象(系統已經幫咱們建立 了);在其它線程裏,若是建立Handler時不傳入Looper對象,那麼,這個Handler將不能接收處理消息。在這種狀況下,通用的做法是:

 
 1  class LooperThread extends Thread {  2       public Handler mHandler;  3       public void run() {  4  Looper.prepare();  5             mHandler = new Handler() {  6                public void handleMessage(Message msg) {  7                // process incoming messages here 
 8  }  9  }; 10  Looper.loop(); 11  } 12 } 

 

在建立Handler以前,爲該線程準備好一個Looper(Looper.prepare),而後讓這個Looper跑起來(Looper.loop),抽取Message,這樣,Handler才能正常工做。
所以,Handler處理消息老是在建立Handler的線程裏運行。而咱們的消息處理中,不乏更新UI的操做,不正確的線程直接更新UI將引起異常。所以,須要時刻關心Handler在哪一個線程裏建立的。

 

     1,MessageQueue與Message的關係

Message中文是消息,及線程處理的最小單元,裏面帶有處理的數據集,或還帶有操做,及告訴目的地要作什麼事情,   每一個MessageQueue裏包含有Message。每一個Message不是直接插入到MessageQueue裏的,而是經過MessageQueue.IdleHandler 與looper一塊兒工做,把Message放到MessageQueue裏,及addIdleHandler(MessageQueue.IdleHandler handler) 和removeIdleHandler(MessageQueue.IdleHandler handler) 方法,把MessageQueue.IdleHandler壓入到MessageQueu裏。

 

        2,Thread和HandlerThread的關係

        HandlerThread就是帶有Looper循環的Thread.

 

        3,Looper介紹

        Looper即一個循環,必須綁定到一個固定的線程裏,經過getThread()方法能夠得到該looper綁定的Thread對象,經過 getMainLooper()得到主線程裏的looper對象,myLooper()能夠得到當前線程裏的looper對象,經過myQueue()方 法能夠得到當前線程裏的messageQueue對象。

       

        4,Thread、HandlerThread、和Looper的關係的關係

        通常聲明一個thread是沒有帶looper循環的,可是能夠經過Looper.prepare()方法給一個線程加上 looper;Looper.loop()執行該looper綁定的線程裏的messageQueue,直到該loopger結 束;Loop.quit()結束該循環,實例代碼以下:

 
 1  class LooperThread extends Thread {  2       public Handler mHandler;  3       
 4       public void run() {  5  Looper.prepare();  6           
 7           mHandler = new Handler() {  8               public void handleMessage(Message msg) {  9                   // process incoming messages here
10  } 11  }; 12           
13  Looper.loop(); 14  } 15   }
 

     

    5,Handler和Thread HandlerThread Looper Message MessageQueue的關係

它把消息發送到該生成它的線程裏的MessageQueue裏,而後當Message出隊列的時候,就執行該消息。
post(Runnable), , ,是用來處理runnable對象的;postAtTime(Runnable, long)postDelayed(Runnable, long)
sendEmptyMessage(int), , , and sendMessage(Message)sendMessageAtTime(Message, long)sendMessageDelayed(Message, long)方法是
能夠經過handleMessage (Message msg) 方法來接收消息。
實例化:Handler(Looper looper) 



 

二. 多線程與異步

Main Thread & UI Thread

當程序啓動的時候android會自動建立一個進程和一個線程,這個線程負責界面更新,收集系統事件和用戶的操做事件等並分配給對應的組件,因此這個線程很是重要 被稱爲主線程,由於所的和UI有關的操做都是在這個線程當中進行的因此也被稱做UI線程。因此說默認狀況下主線程和UI線程指的是同一個線程。

Android的UI系統參考了不少SWT的設計模式。好比,UI線程機制,底層JNI實現 etc.

Android 的UI系統是非線程安全的,意思是說只有建立UI的線程(也就是主線程)才能夠對UI進程操做。若是咱們在其它線程中執行了一些操做,而這些操做的結果又須要經過UI展示給用戶,必需把這更新UI的操做轉移到到UI線程中執行。

不少Java起步的程序員對UI線程中的"消息循環"會感受陌生。其實就是在線程內部有一個死循環一直監聽系統事件(用戶的操做等)並把任務分發給對應的 組件(有興趣的能夠看看NDK附帶的native-activity的一個sample,在c中的實現方式就是一個while(1)的死循環)。主線程通 過Looper實現了消息的循環處理。

The ralationship between Handler,Message,MessageQueue and Looper?

若是一個線程裏邊有一個死循環,那麼這個循環就會一直在死循環裏邊循環,而且這個線程不會過多的cpu資源,那麼這個線程確定的阻塞的。若是線程只是一直 循環沒有什麼意義,實際狀況一般須要線程根據不一樣的條件運行不一樣的方法。咱們一般的做法可能會加一個switch開關,根據條件的不一樣去調用不一樣的方法。

線程間通訊(最多見的就是,worker線程須要更新UI),這個時候實際是包含兩個內容:一,數據的傳遞;二,方法的傳遞; Android中的Message用於數據傳遞,而Handler就是方法傳遞(實際上是方法的執行者,Handler會把這個方法放到Handler所在 的線程當中去執行);MessageQueue是Message的容器和Java中的Queue同樣都是容器,只不過Message Queue是專門用於裝載Message的容器。Looper則是一個線程中的死循環用於管理MessageQueue,它負責阻塞讀取 MessageQueue中的信息(若是MessageQueue中沒有信息會一直在那裏),挨個讀取並把這個Message分發給對應的Handler 去執行。

 

首先看一下mHandler.obtainMessage(SHOW_ALERT, Greetings).sendToTarget();會執行什麼。

經過查看Handler的源碼發現執行了下邊的代碼。

1 public final Message obtainMessage(int what, Object obj){ 2     return Message.obtain(this, what, obj); 3 }
 
 
  接着查看Message中的代碼
 1 public static Message obtain(Handler h, int what, Object obj) {  2     Message m = obtain();  3     m.target = h;  4     m.what = what;  5     m.obj = obj;  6     return m;  7 }  8 /**
 9 * Return a new Message instance from the global pool. Allows us to 10 * avoid allocating new objects in many cases. 11 */
12 public static Message obtain() { 13     synchronized (mPoolSync) { 14         if (mPool != null) { 15             Message m = mPool; 16             mPool = m.next; 17             m.next = null; 18             return m; 19  } 20  } 21     return new Message(); 22 }

 

  看到這裏咱們應該明白爲何Google建議咱們使用obtainMessage而不是new一個Message.這也是符合了Android中的對象回收機制。

 1 public void sendToTarget() {  2 
 3     target.sendMessage(this);//targe就是一個Handler
 4 
 5 }  6 sendMessage()會調用下面的sendMessageAtTime()把Message加入MessagQueue;  7 
 8 public boolean sendMessageAtTime(Message msg, long uptimeMillis){  9     boolean sent = false; 10     MessageQueue queue = mQueue; 11     if (queue != null) { 12         msg.target = this; 13         sent = queue.enqueueMessage(msg, uptimeMillis); 14     }else { 15         RuntimeException e = new RuntimeException( 16                 this + " sendMessageAtTime() called with no mQueue"); 17         Log.w("Looper", e.getMessage(), e); 18  } 19     return sent; 20 }

 到此咱們的Message對象被加入到了Handler所在線程(也就是主線程)中的MessageQueue這個存儲和管理Message的容器當中。下一步就該由Looper接手一個一個的取出Message對象處理了。Looper最主要的方法就是loop()方法

 

 1 public static final void loop() {  2     Looper me = myLooper();  3     MessageQueue queue = me.mQueue;  4     while (true) {//死循環
 5         Message msg = queue.next(); // might block
 6            if (msg != null) {  7             if (msg.target == null) {//退出死循環的機制  8             // No target is a magic identifier for the quit message.
 9         return; 10  } 11          if (me.mLogging!= null) me.mLogging.println( 12             ">>>>> Dispatching to " + msg.target + " "
13                  + msg.callback + ": " + msg.what 14  ); 15         msg.target.dispatchMessage(msg);//target of a msg is a Handler
16         if (me.mLogging!= null) me.mLogging.println( 17              " Finished to    " + msg.target + " "
18             + msg.callback);//msg.callback is a Runnable
19  msg.recycle(); 20  } 21  } 22 }

 Looper會一直阻塞讀取MessagQueue中的Message對象(Message msg = queue.next()),當讀取到一個Message時就會調用msg.target.dispatchMessage(msg)把這個 Message分發給對應的Handler去處理,等Handler把任務處理完了再接着讀取下一個Message對象並處理。

 1 /**
 2 * Handle system messages here.  3 */
 4 public void dispatchMessage(Message msg) {  5     if (msg.callback != null) {  6         handleCallback(msg);// call the run method of the runnable object I guess
 7     } else {  8         if (mCallback != null) {  9             if (mCallback.handleMessage(msg)) { 10             return; 11  } 12  } 13  handleMessage(msg); 14  } 15 }

 最後回來了咱們的handlerMessage(msg);這個方法中。若是是用的不是sendMessage是是Hadler.post(Runnable)會調用

 
 
1 private final void handleCallback(Message message) { 2  message.callback.run(); 3 }
 
 

這就是爲何在Handler中post的Runnable不會開啓一個新的線程的緣由。通過上面的追蹤咱們應該能明白不是全部 的線程均可以有Handler去執行handlerMessage或者處理Runnalbe的。其必要條件就是這個線程要有一個一直循環的 Looper.Looper一直循環確定要有一個方法能夠退出循環。

 

Thread,Looper,Handler,Message,MessageQueue之間的關係 - Gobby.X - Just Miss.Gobby

當咱們調用msg.sendToTarget()的時候,咱們的msg對象應付被壓入MessageQueue的尾部。Looper在 MessageQueue的另外一端一個一個的讀取信息並處理。根據msg的target屬性把cpu分配給對應的Handler去執行任務,這時 Handler會根據msg中的屬性調用msg.handleMsg()或者msg.callback.run();當一個msg中的消息處理完返回以後 Looper會把這個msg放入msgPool當中方便下次再重複利用。從而減小對象的建立。Looper再從MessageQueue中讀取下一個信 息,如此反覆。。

理解了這些其實就不難想象ANR是如何實現的了。當用戶執行操做(好比點擊了一個按鈕)系統會生成一個Message對象,把用戶操做的信息寫入 Message對象,並把這個Message對象壓入MessageQueue隊列的尾部。系統過一段時間(通常是五秒)後會再來檢查,剛剛放入的信息是 不是已經被處理了,若是信息還在隊列中就代表。處理前面信息的過程中發生的阻塞,用戶的操做沒有及時獲得響應。系統彈出ANR對話框。

 

做個總結:

  由於UI線程須要保持一直運行的狀態,因此要有一個循環保持這個線程不會死掉,但這個線程又必需阻塞,以減小cpu的消耗。android中的這個循 環就是經過Looper實現的。有了這個 Looper,Looper就佔據了整個線程,致使全部的方法想在些線程中運行就必需經過這個Looper,因此要有個方法能夠進入這個Looper的內 部。MessageQueue就擔當了這個通道 的角色。Message擔當了集合的角色。全部在UI線程中運行的方法都必需經過MessageQueue進入Looper內部,無論 是用戶定義的方法仍是系統事件包括onCreate(),onStop(),用戶點擊事件etc..

 

 

三.Android中消息系統模型和Handler Looper

消息系統的基本原理和構成

       從通常的消息系統模型的創建大體構成如下幾個部分:

    l  消息原型

    l  消息隊列

    l  發送消息

    l  消息循環

    l  消息獲取

    l  消息派發

    l  消息處理

 

大體模型圖以下:

    

 

       消息系統模型通常會包括以上七個部分(消息原型,消息隊列,消息發送,消息循環,消息獲取,消息派發,消息處理)。實際上的核心是消息隊列和消息循環,其他部分都是圍繞這兩部分進行的。

  從前面文檔的分析中咱們知道Handler就是用來創建消息處理的系統模型,那麼和這裏基本消息系統模型相比,那麼Handler又是如何囊括這七個部分的呢?

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

    Handler,Message,MessageQueue,Looper;

  •   Message就是消息原型,包含消息描述和數據,
  •   MessageQueue就是消息隊列,
  •   Looper完成消息循環
  •   Handler就是駕馭整個消息系統模型,統領Message,MessgeQueue和Looper;

 

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

 

 

 

 

四. Handler工做原理分析

  要了解Handler工做原理,先看一下這個系統模型具體組成的層次結構框架是個什麼樣的。

 

      

 

  實現Thread的消息循環和消息派發,缺省狀況下Thread是沒有這個消息循環的既沒有Looper;須要主動去建立,而後啓動Looper的消息循環loop;與外部的交互經過Handler進行;消息隊列,由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.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調用MessageQueue的enqueueMessage方法:

       

 1 final boolean enqueueMessage(Message msg, long when) {  2 
 3               Message p = mMessages;  4 
 5               if (p == null || when == 0 || when < p.when) {  6                  msg.next = p;  7                  mMessages = msg;  8  }  9               else { 10 
11                      Message prev = null; 12                      while (p != null && p.when <= when) { 13                             prev = p; 14                             p = p.next; 15  } 16 
17                      msg.next = prev.next; 18                      prev.next = msg; 19  } 20  …… 21   }

 

能夠看到是按照時間順序將消息加入到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進行線程之間有消息傳遞。感受這個利用的很好很巧妙。

相關文章
相關標籤/搜索