Handler訊息機制完全解析Handler解析

codeGoogle發表於2019-02-27

Handler

Handler總是依附於建立時所在的執行緒,比如我們的Handler是在主執行緒中建立的,而在子執行緒中又無法直接對UI進行操作,於是我們就通過一系列的傳送訊息、入隊、出隊等環節,最後呼叫到了Handler的handleMessage()方法中,這時的handleMessage()方法已經是在主執行緒中執行的,因而我們當然可以在這裡進行UI操作了。整個非同步訊息處理流程的示意圖如下圖所示:

非同步訊息處理流程
非同步訊息處理流程

Handler

這便是我們平時直接使用的主角。繼承Handler
重寫其handleMessage()
方法來處理訊息,在需要的時候呼叫sendMessage()
來發訊息,剩下的就不用管了。現在來看看“我們不用管”的這部分都幹了點啥。

構造方法

所有的構造方法最終會會呼叫兩個實現,如果制定了Looper,則會呼叫三個引數的過載,否則會呼叫兩個引數的過載。而後者則會呼叫Lopper.myLooper()
來獲取looper。兩個構造方法除了給mLooper
賦值外,還給mQueue
賦值為mLooper.mQueue
;給mCallback
賦值為指定的callback或null;給mAsynchronous
賦值為指定的boolean或false。 在兩個引數的構造方法中,給上述四個成員賦值前有段if(FIND_POTENTIAL_LEAKS){}
包裹的程式碼段,該變數定義為private static final boolean FIND_POTENTIAL_LEAKS = false;
因此推斷這部分是開發時除錯用的,此處不做理會。

建立訊息obtainMessage()

根據原始碼可以看出,所有該方法的過載都呼叫了Message.obtain()
對應的過載,可以看Message.obtain()的來龍去脈來了解,此處不再贅述。需要注意的是,每個過載都傳入了this
引數並賦值給了message的target
。這裡先記著就行,後面會介紹如何通過target
呼叫dispatchMessage()
處理訊息。

傳送訊息sendMessage()

所有的sendEmptyMessage()
過載與sendMessageXXX()
以及postXXX()
最終都會呼叫enqueueMessage()
方法,該方法則呼叫queue.enqueueMessage()
方法將訊息新增到訊息佇列。關於訊息佇列如何管理訊息可以看MessageQueue的佇列管理一文。

移除訊息removeMessage()

所有的removeMessages()
過載與removeCallbacks()
過載最終都是呼叫mQueue.removeMessages()
方法,即通過MessageQueue來實現該操作。詳細分析可以看MessageQueue的佇列管理一文。

處理訊息dispatchMessage()

訊息處理最開始被呼叫的不是handleXXX()
方法,而是dispatchMessage()
方法。該方法會根據訊息是否有callback
來判斷該交給handleCallback()
還是handleMessage()
。前者直接呼叫引數中message
的message.calback.run()
解決問題,後者則是空方法體,需要我們開發者自己重寫。

Handler一些特點

  • handler可以分發Message物件和Runnable物件到主執行緒中, 每個Handler例項,都會繫結到建立他的執行緒中(一般是位於主執行緒),它有兩個作用:

    • (1)安排訊息或Runnable 在某個主執行緒中某個地方執行;
    • (2)安排一個動作在不同的執行緒中執行。

Handler例項

  • 子類需要繼承Hendler類,並重寫handleMessage(Message msg) 方法, 用於接受執行緒資料。

  • 以下為一個例項,它實現的功能為:通過執行緒修改介面Button的內容

    public class MyHandlerActivity extends Activity { 
      Button button; 
      MyHandler myHandler; 
    
      protected void onCreate(Bundle savedInstanceState) { 
          super。onCreate(savedInstanceState); 
          setContentView(R。layout。handlertest); 
    
          button = (Button) findViewById(R。id。button); 
          myHandler = new MyHandler(); 
          // 當建立一個新的Handler例項時, 它會繫結到當前執行緒和訊息的佇列中,開始分發資料 
          // Handler有兩個作用, (1) : 定時執行Message和Runnalbe 物件 
          // (2): 讓一個動作,在不同的執行緒中執行。 
    
          // 它安排訊息,用以下方法 
          // post(Runnable) 
          // postAtTime(Runnable,long) 
          // postDelayed(Runnable,long) 
          // sendEmptyMessage(int) 
          // sendMessage(Message); 
          // sendMessageAtTime(Message,long) 
          // sendMessageDelayed(Message,long) 
    
          // 以上方法以 post開頭的允許你處理Runnable物件 
          //sendMessage()允許你處理Message物件(Message裡可以包含資料,) 
    
          MyThread m = new MyThread(); 
          new Thread(m)。start(); 
      } 
    
      /** 
      * 接受訊息,處理訊息 ,此Handler會與當前主執行緒一塊執行 
      * */ 
    
      class MyHandler extends Handler { 
          public MyHandler() { 
          } 
    
          public MyHandler(Looper L) { 
              super(L); 
          } 
    
          // 子類必須重寫此方法,接受資料 
          @Override 
          public void handleMessage(Message msg) { 
              // TODO Auto-generated method stub 
              Log。d("MyHandler""handleMessage。。。。。。"); 
              super。handleMessage(msg); 
              // 此處可以更新UI 
              Bundle b = msg。getData(); 
              String color = b。getString("color"); 
              MyHandlerActivity。this。button。append(color); 
    
          } 
      } 
    
      class MyThread implements Runnable { 
          public void run() { 
    
              try { 
                  Thread。sleep(10000); 
              } catch (InterruptedException e) { 
                  // TODO Auto-generated catch block 
                  e。printStackTrace(); 
              } 
    
              Log。d("thread。。。。。。。""mThread。。。。。。。。"); 
              Message msg = new Message(); 
              Bundle b = new Bundle();// 存放資料 
              b。putString("color""我的"); 
              msg。setData(b); 
    
              MyHandlerActivity。this。myHandler。sendMessage(msg); // 向Handler傳送訊息,更新UI 
    
          } 
      } 
    }複製程式碼

    如果你覺
    得此文對您有所幫助,歡迎入群 QQ交流群 :232203809
    微信公眾號:終端研發部

技術+職場
技術+職場

相關文章