Android-初識Handler,Looper,Message(-) 源碼

來源:互聯網
上載者:User

本文只是表面的帶大家瀏覽下Handler,Looper,Message的源碼

android的訊息處理有三個核心類:Looper,Handler和Message。其實還有一個Message Queue(訊息佇列),

非同步處理大師 Handler:

什麼是handler?handler扮演了往MQ上添加訊息和處理訊息的角色(只處理由自己發出的訊息),即通知MQ它要執行一個任務(sendMessage),並在loop到自己的時候執行該任務(handleMessage),整個過程是非同步。handler建立時會關聯一個looper,預設的構造方法將關聯當前線程的looper,不過這也是可以set的。預設的構造方法:

public class handler {         final MessageQueue mQueue;  // 關聯的MQ       final Looper mLooper;  // 關聯的looper       final Callback mCallback;       // 其他屬性         public Handler() {           if (FIND_POTENTIAL_LEAKS) { // 沒看懂,直接略過,,,               final Class<? extends Handler> klass = getClass();               if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&                       (klass.getModifiers() & Modifier.STATIC) == 0) {                   Log.w(TAG, "The following Handler class should be static or leaks might occur: " +                       klass.getCanonicalName());               }           }           // 預設將關聯當前線程的looper           mLooper = Looper.myLooper();           // looper不可為空,即該預設的構造方法只能在looper線程中使用   
        //UI主線程中預設帶有一個Looper        if (mLooper == null) {               throw new RuntimeException(//不能在沒有Looper的線程上建立Handler,                   "Can't create handler inside thread that has not called Looper.prepare()");           }           // 重要!!!直接把關聯looper的MQ作為自己的MQ,因此它的訊息將發送到關聯looper的MQ上           mQueue = mLooper.mQueue;           mCallback = null;       }         // 其他方法   }  

當然這隻是Handler的一個構造方法。Handler本身有四個建構函式,其他其他的三個你可以通過查看源碼來解析,大致雷同。

Handler發送訊息

有了handler之後,我們就可以使用 post(Runnabl),sendMessage(Message)這些方法向MQ上發送訊息了。光看這些API你可能會覺得handler能發兩種訊息,一種是Runnable對象,一種是message對象,這是直觀的理解,但其實post發出的Runnable對象最後都被封裝成message對象了,見源碼:
Post發送的形式

public final boolean post(Runnable r){//使用Post發送訊息      return  sendMessageDelayed(getPostMessage(r), 0);}
private final Message getPostMessage(Runnable r) {//把一個Runnable包轉成一個Message       Message m = Message.obtain();       m.callback = r;       return m;}
public final boolean sendMessageDelayed(Message msg, long delayMillis){       if (delayMillis < 0) {           delayMillis = 0;       }       return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);}
public boolean sendMessageAtTime(Message msg, long uptimeMillis){        boolean sent = false;        MessageQueue queue = mQueue;        if (queue != null) {
/*該handler對象,這確保了looper執行到該message時能找到處理它的handler,直白點就是ABC三個Handler發送訊息,最終執行的時候Message訊息
也是由他們本身來執行,而不會發生A接受到B發送的Message之類的情況*/            msg.target = this;//
            sent = queue.enqueueMessage(msg, uptimeMillis);//壓入訊息佇列        }else {            RuntimeException e = new RuntimeException(                this + " sendMessageAtTime() called with no mQueue");            Log.w("Looper", e.getMessage(), e);        }        return sent;}

sendMessage(Message)形式

 public final boolean sendMessage(Message msg){        return sendMessageDelayed(msg, 0);}
public final boolean sendMessageDelayed(Message msg, long delayMillis){       if (delayMillis < 0) {           delayMillis = 0;       }       return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }

從源碼中我們中我們可以很清晰的看到無論是用psot(Runnable)還是使用sendMessage(Message)方法,最後他們都會調用到同一個方法壓入都一個隊列中去。

Handler處理訊息

那handler如何處理訊息。訊息的處理是通過核心方法是通過dispatchMessage(Message)來進行處理的,源碼如下:

public void dispatchMessage(Message msg) {        if (msg.callback != null) {//post(Runnable)形式最終調用到這個方法            handleCallback(msg);        } else {
/* 這種方法允許讓activity等來實現Handler.Callback介面或者構造Handler(Callback,避免了自己編寫handler重寫handleMessage方法*/            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {                    return;                }            }            handleMessage(msg);//優先等級最低的就是 重寫HandlerMessage方法了        }    }

封裝任務Message

Message的源碼中沒有特別的方法,對於Message我們應該記住下面的幾個知識點(等待大家補充)

1.儘管我們可以直接instance一個Message,但我們最好通過Message.obtain()來從訊息池中獲得空訊息對象,以節省資源。

2.如果你的message只需要攜帶簡單的int資訊,請優先使用Message.arg1和Message.arg2來傳遞資訊,這比用Bundle更省記憶體

3.擅用message.what欄位表示code,
即這個訊息具體是什麼類型的訊息.
每個what都在其handler的namespace中,
我們只需要確保將由同一個handler處理的訊息的what屬性不重複就可以.相當於判別類型

4.message.When 它大小由小到大排列, 排在最前面的訊息會首先得到處理,
因此可以說訊息佇列並不是一個嚴格的先進先出的隊列.

5.message.target 確定了最終你執行的時候由那個Handler來執行這個Message。一般來說誰壓入隊列就讓誰在抽取出來的時候去執行。通過上面的源碼我們可以查詢到

Looper管道哥

首先明確一點Activity本身在啟動的時候預設給了他一個Looper

Looper構造:

  private Looper() {        mQueue = new MessageQueue();//初始化Looper的時候的我們就給這個Looper配了一個MQ隊列,一一對應        mRun = true;        mThread = Thread.currentThread();//綁定他所屬的線程    }
 // 我們調用該方法會在調用線程的TLS中建立Looper對象       public static final void prepare() {           if (sThreadLocal.get() != null) {               // 試圖在有Looper的線程中再次建立Looper將拋出異常               throw new RuntimeException("Only one Looper may be created per thread");           }           sThreadLocal.set(new Looper());       }   

 public static final void loop() {          Looper me = myLooper();//從該線程中取出對應的looper對象           MessageQueue queue = me.mQueue;//取訊息佇列對象...           while (true) {              Message msg = queue.next(); // might block 這個方法還不是很懂。出去一個待處理的Message              //if (!me.mRun) {            //    break;               //}               if (msg != null) {                  if (msg.target == null) {                      // No target is a magic identifier for the quit message.                       return;                  }                  if (me.mLogging!= null) me.mLogging.println(                          ">>>>> Dispatching to " + msg.target + " "                          + msg.callback + ": " + msg.what                          );                  msg.target.dispatchMessage(msg); //訊息的抽取。最終的施行執行方法                if (me.mLogging!= null) me.mLogging.println(                          "<<<<< Finished to    " + msg.target + " "                          + msg.callback);                  msg.recycle();              }          }      }  

以上就是對Handler和Message還有Looper的源碼的表面認識

 

相關文章

聯繫我們

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

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

Tags Index: