一定搞懂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語句扛稽,
                  所以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)O!县貌!
                  /*把當(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)系作者
  • 序言:七十年代末现拒,一起剝皮案震驚了整個(gè)濱河市辣垒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌印蔬,老刑警劉巖勋桶,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異侥猬,居然都是意外死亡例驹,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門退唠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鹃锈,“玉大人,你說我怎么就攤上這事瞧预∈赫” “怎么了仅政?”我有些...
    開封第一講書人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長盆驹。 經(jīng)常有香客問我圆丹,道長,這世上最難降的妖魔是什么躯喇? 我笑而不...
    開封第一講書人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任辫封,我火速辦了婚禮,結(jié)果婚禮上廉丽,老公的妹妹穿的比我還像新娘倦微。我一直安慰自己,他們只是感情好雅倒,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開白布璃诀。 她就那樣靜靜地躺著弧可,像睡著了一般蔑匣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上棕诵,一...
    開封第一講書人閱讀 51,521評(píng)論 1 304
  • 那天裁良,我揣著相機(jī)與錄音,去河邊找鬼校套。 笑死价脾,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的笛匙。 我是一名探鬼主播侨把,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼妹孙!你這毒婦竟也來了秋柄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤蠢正,失蹤者是張志新(化名)和其女友劉穎骇笔,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嚣崭,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡笨触,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了雹舀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片芦劣。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖说榆,靈堂內(nèi)的尸體忽然破棺而出持寄,到底是詐尸還是另有隱情源梭,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布稍味,位于F島的核電站废麻,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏模庐。R本人自食惡果不足惜烛愧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望掂碱。 院中可真熱鬧怜姿,春花似錦、人聲如沸疼燥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽醉者。三九已至但狭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間撬即,已是汗流浹背立磁。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留剥槐,地道東北人唱歧。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像粒竖,于是被迫代替她去往敵國和親颅崩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容