Handler消息傳遞機制

       出於性能優化考慮,Android的UI操做並非線程安全的,這意味着若是有多個線程併發操做UI組件,可能致使線程安全問題。爲了解決這個問題,Android制定了一條簡單的規則:只容許UI線程修改Activity裏的UI組件。程序員

       當一個程序第一次啓動時,Android會同時啓動一條主線程(Main Thread),主線程主要負責處理與UI相關的事件,如用戶的按鍵事件、用戶接觸屏幕的事件及屏幕繪圖事件,並把相關的事件分發到對應的組件進行處理。因此主線程一般又被叫作UI線程。安全

       Android的消息傳遞機制是另外一種形式的「事件處理」,這種機制主要是爲了解決Android應用的多線程問題——Android平臺只容許UI線程修改Activity裏的UI組件,這樣就會致使新啓動的線程沒法動態改變界面組件的屬性值。但在實際Android應用開發中,尤爲是涉及動畫的遊戲開發中,須要讓新啓動的線程週期性地改變界面組件的屬性值,這就須要藉助於Handler的消息傳遞機制來實現了。性能優化

Handler類簡介

   Handler類的主要做用有兩個:多線程

     一、在新啓動的線程中發送消息。併發

     二、在主線程中獲取、處理消息。oop

   爲了讓主線程能「適時」地處理新啓動的線程所發送的消息,顯然只能經過回調的方式來實現——開發者只要重寫 Handler 類中處理消息的方法,當新啓動的線程發送消息時,消息會發送到與之關聯的 MessageQueue ,而 Handler 會不斷地從MessageQueue 中獲取並處理消息——這將致使 Handler 類中處理消息的方法被回調。性能

Handler類包含以下方法用於發送、處理消息。優化

  一、void handleMessage(Message msg):處理消息的方法。該方法一般用於被重寫。動畫

  二、final boolean hasMessages(int what):檢查消息隊列中是否包含what屬性爲指定值得消息。spa

  三、final boolean hsaMessages(int what,Object object):檢查消息隊列中是否包含what屬性爲指定值且object屬性爲指定對象的消息。

  四、多個重載的 Message obtainMessage():獲取消息。

  五、sendEmptyMessage(int what):發送空消息。

  六、final boolean sendEmptyMessageDelayed(int what,long delayMills):指定多少毫秒以後發送空消息。

  七、final boolean sendMessage(Message msg):當即發送消息。

  八、final boolean sendMessageDelayed(Message msg,long delayMillis):指定多少毫秒以後發送消息。

藉助於上面這些方法,程序能夠方便地利用Handler 類進行消息傳遞。

Handler、Loop、MessageQueue的工做原理

  爲了更好的理解Handler的工做原理,先介紹一下與Handler一塊兒工做的幾個組件。

  一、Message:Handler 接受和處理的消息對象

  二、Looper:每一個線程只能擁有一個Looper。它的loop方法負責讀取MessageQueue中的消息,讀到消息以後就把消息交給發送消息的Handler進行處理。

  三、MessageQueue:消息隊列,它採用先進先出的方法來管理Message。程序建立Looper對象時會在它的構造器中建立Looper對象。Looper 提供的構造器源代碼以下:

1 private Looper()
2 {
3   mQueue=new MessageQueue();
4   mRun=true;
5   mThread=Thread.currentThread();
6 }

   該構造器使用了 private 修飾,代表程序員沒法經過構造器建立Looper對象。從上面的代碼中不難看出,程序在初始化Looper時會建立一個與之關聯的 MessageQueue ,這個MessageQueue就負責管理消息。

  一、Handler:它的做用有兩個——發送消息和處理消息,程序使用Handler發送消息,被Handler發送的消息必須被送到指定的MessageQueue。也就是說,若是但願Handler正常工做,必須在當前線程中有一個MessageQueue,不然消息就沒有MessageQueue進行保存了。不過MessageQueue是由Looper負責管理的,也就是說,若是但願Handler正常工做,必須在當前線程中有一個Looper對象,爲了保證當前線程中有Looper對象,能夠分以下兩種狀況處理。

  一、主UI線程中,系統已經初始化了一個Looper對象,所以程序直接建立Handler便可,而後就可經過Handler來發送消息、處理消息。

  二、程序員本身啓動的子線程,程序員必須本身建立一個Looper對象,並啓動它。建立Looper對象調用它的prepare()方法便可。

prepare()方法保證每一個線程最多隻有一個Looper對象。prepare()方法的源代碼以下:

public static final void prepare()
{
    if(sThreadLocal.get()!=null)
    {
        throw new RuntimeException("Only one Looper may be createed per thread");
    }
    sThreadLocal.set(new Looper());
}

   而後調用Looper 的靜態 loop() 方法來啓動它。loop()方法使用一個死循環不斷取出MessageQueue 中的消息,並將取出的消息分給對應的Handler進行處理。

 

  概括起來,Looper、MessageQueue、Handler 各自的做用以下:

  一、Looper:每一個線程只有一個Looper,它負責管理 MessageQueue ,會不斷地從MessageQueue中取出消息。並將消息分給對應的Handler處理。

  二、MessageQueue:由Looper負責管理。它採用先進先出的方法來管理Message。

  三、Handler:它能把消息發送給Looper管理的MessageQueue,並負責處理Looper分給它的消息。

 在線程中使用Handler的步驟以下:

     一、調用Looper的prepare()方法爲當前線程建立Looper對象,建立Looper對象時,它的構造器會建立與之配套的MessageQueue。

  二、有了Looper以後,建立Handler子類的實例,重寫handlerMessage()方法,該方法負責處理來自於其餘線程的消息。

  三、調用Looper的loop()方法啓動Looper。

相關文章
相關標籤/搜索