一定搞懂Handler消息處理機(jī)制系列之「02.Message入列」

Message入列

判斷新創(chuàng)建Message處于隊(duì)列中的位置,并插入相應(yīng)位置

//截取自MessageQueue.enqueueMessage()方法來舉例(刪除了部分與此次無關(guān)代碼)
boolean enqueueMessage(Message msg, long when) {
        synchronized (this) {
              //標(biāo)記傳入的msg被使用
            msg.markInUse();
            msg.when = when;
              //創(chuàng)建臨時(shí)變量來儲(chǔ)存消息隊(duì)列中的Message對(duì)象
            Message p = mMessages;
            boolean needWake;
                 /*   
                  * 當(dāng)消息隊(duì)列中沒有消息
                  * 或傳入Message的觸發(fā)時(shí)間為0時(shí)
                * 或傳入Message的觸發(fā)時(shí)間小于當(dāng)前消息隊(duì)列中的Message的觸發(fā)時(shí)間
                */
            if (p == null || when == 0 || when < p.when) {
                //把傳入的Message放入當(dāng)前消息隊(duì)列中的Message之前
                msg.next = p;
                  //把當(dāng)前消息隊(duì)列中的Message對(duì)象重置為傳入的Message對(duì)象
                mMessages = msg;
                needWake = mBlocked;
            }  else {
               /* 
                  * 當(dāng)消息隊(duì)列中有消息
                  * 且傳入Message的觸發(fā)時(shí)間不為0時(shí)
                * 且傳入Message的觸發(fā)時(shí)間大于當(dāng)前消息隊(duì)列中的Message的觸發(fā)時(shí)間
                */
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
              //創(chuàng)建一個(gè)臨時(shí)變量
                Message prev;
                for (;;) {
                      //儲(chǔ)存臨時(shí)變量p(當(dāng)前消息隊(duì)列中的Messge)
                    prev = p;
                      //讓p指向自己在消息隊(duì)列中的下一條消息
                    p = p.next;
                      //當(dāng)p為null時(shí),說明prev是當(dāng)前消息隊(duì)列中的最后一條消息
                      //或者傳入Message的觸發(fā)時(shí)間小于p的觸發(fā)時(shí)間時(shí)終止循環(huán)
                    if (p == null || when < p.when) {
                        break;
                    }
                }
                  /* 此時(shí)的p滿足以下兩個(gè)條件中的一個(gè):
                   *  1.p為null時(shí),說明prev是當(dāng)前消息隊(duì)列中的最后一條消息(因?yàn)閜為null,所以prev不為
                   null且prev的觸發(fā)時(shí)間小于傳入Message的觸發(fā)時(shí)間,所以傳入Message的為消息隊(duì)列中的最
                   后一條消息,prev為傳入Message的上一條消息)
                   *  2.p的觸發(fā)時(shí)間大于傳入Message的觸發(fā)時(shí)間(因?yàn)閜的觸發(fā)時(shí)間大于傳入Message的觸發(fā)時(shí)
                間,所以p在消息隊(duì)列中是傳入Message的下一條消息,因?yàn)樵谏弦淮窝h(huán)中沒有進(jìn)入if語(yǔ)句,
                  所以prev不為null且觸發(fā)時(shí)間小于傳入Message對(duì)象的觸發(fā)時(shí)間,所以prev在消息隊(duì)列中處于
                   傳入Message的上一條)
                   */ 
                msg.next = p;
                prev.next = msg;
            }
        }
        return true;
    }

Message的獲取方式

Message的獲取方式除了new Message這種方式,Message類還提供了obtain方法來獲取Message

//Message類中有一個(gè)靜態(tài)全局變量來儲(chǔ)存空閑或者回收的Message對(duì)象
private static Message sPool;
public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; 
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

這種方式是把靜態(tài)全局變量sPool(這里可以把這個(gè)Message看做當(dāng)前消息池中的第一條消息)標(biāo)記為未使用然后返回,如果sPool為null才會(huì)創(chuàng)建新的Message對(duì)象,這樣不會(huì)造成資源的浪費(fèi),避免創(chuàng)建太多Message對(duì)象。關(guān)于為什么sPool會(huì)是被回收的Message對(duì)象,上源碼:

      //此方法為Message的回收方法
  public void recycle() {
          //在回收的方法
        recycleUnchecked();
    };
  void recycleUnchecked() {
          //這里在做一些重置的工作
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = -1;
        when = 0;
        target = null;
        callback = null;
        data = null;

        synchronized (sPoolSync) {
          //當(dāng)消息池里消息的數(shù)量小于消息池的最大容量時(shí)
            if (sPoolSize < MAX_POOL_SIZE) {
                  //重點(diǎn)?。?!
                  /*把當(dāng)前消息池中第一條消息(也就是sPool)置為當(dāng)前消息的下一條消息(sPool為
              全局靜態(tài)變量,所有Message都共用這一個(gè)sPool)*/
                next = sPool;
                  /*把當(dāng)前消息置為消息池中第一條消息(因?yàn)樯弦徊襟E已經(jīng)把原來消息池中的第一條消息置為
              了當(dāng)前消息的下一條消息,現(xiàn)在把當(dāng)前消息置為消息池中的第一條消息,所以sPool永遠(yuǎn)代表
              消息池中的第一條消息)*/
                sPool = this;
                sPoolSize++;
            }
        }
    }

可以看出Message在回收過程中,只要消息池的數(shù)量小于消息池的最大容量時(shí),就是把當(dāng)前Message放入消息池中。

Message在MessageQueue隊(duì)列中存在的形式

從Message入列方式我們也看出,再有新消息進(jìn)入隊(duì)列時(shí),是先判斷新消息的觸發(fā)時(shí)間,找出消息應(yīng)該插入消息隊(duì)列的位置,把這個(gè)位置的消息的next置為本條新消息,然后把新消息的next置為這個(gè)位置的消息的下一條消息。類似以下結(jié)構(gòu)(如果我理解有錯(cuò),歡迎指出)。

message
message

系列目錄:

一定搞懂Handler消息處理機(jī)制系列之「01.Handler消息發(fā)送」

一定搞懂Handler消息處理機(jī)制系列之「02.Message入列」

一定搞懂Handler消息處理機(jī)制系列之「03.MessageQueue與Looper的由來」

一定搞懂Handler消息處理機(jī)制系列之「04.Message是如何觸發(fā)的」

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容