回轉(zhuǎn)壽司你一定吃過(guò)癌压!——Android消息機(jī)制(構(gòu)造)

這是“Android消息機(jī)制”系列的第一篇文章,系列文章目錄如下:

  1. 回轉(zhuǎn)壽司你一定吃過(guò)荆陆!——Android消息機(jī)制(構(gòu)造)
  2. 回轉(zhuǎn)壽司你一定吃過(guò)滩届!——Android消息機(jī)制(分發(fā))
  3. 回轉(zhuǎn)壽司你一定吃過(guò)!——Android消息機(jī)制(處理)

消息機(jī)制的故事


壽司陳放在壽司碟上被啼,壽司碟按先后順序被排成隊(duì)列送上傳送帶帜消。傳送帶被啟動(dòng)后,壽司挨個(gè)呈現(xiàn)到你面前浓体,你有三種享用壽司的方法泡挺。

將Android概念帶入后,就變成了Android消息機(jī)制的故事:
壽司碟 ---> 消息(Message)
隊(duì)列 ---> 消息隊(duì)列(MessageQueue)
傳送帶 ---> 消息泵 (Looper)
壽司 ---> 你關(guān)心的數(shù)據(jù)
享用壽司方法 ---> 處理數(shù)據(jù)方式

暫未找到 Handler 在此場(chǎng)景中對(duì)應(yīng)的實(shí)體命浴。它是一個(gè)更抽象的概念娄猫,它即可以生產(chǎn)壽司,又把壽司送上傳送帶生闲,還定義了怎么享用壽司媳溺。暫且稱它為消息處理器吧。

如果打算自己開(kāi)一家回轉(zhuǎn)壽司店碍讯,下面的問(wèn)題很關(guān)鍵:

  1. 如何生產(chǎn)壽司(如何構(gòu)造消息)
  2. 如何分發(fā)壽司(如何分發(fā)消息)

讓我們帶著這兩個(gè)問(wèn)題悬蔽,去分析一下消息機(jī)制源碼。
(ps: 下文中的 粗斜體字 表示引導(dǎo)源碼閱讀的內(nèi)心戲)

如何構(gòu)造消息


壽司碟是重復(fù)利用的捉兴,享用完壽司后蝎困,它被清洗,然后被存放起來(lái)倍啥,以便再次利用禾乘。沒(méi)有哪個(gè)老板會(huì)在用餐后把壽司碟銷毀,下次要用就買新的逗栽,這樣代價(jià)太大盖袭。
同樣道理,構(gòu)造消息對(duì)象代價(jià)也很大,它是否也像壽司碟一樣可以復(fù)用鳄虱?如果是弟塞,那消息存放在哪里?
讓我們以Handler.obtainMessage()為切入點(diǎn)一探究竟:

public class Handler {
   ...
   public final Message obtainMessage(){
       return Message.obtain(this);
   }
   ...
}

public final class Message implements Parcelable {
  ...
  /**
    * Same as {@link #obtain()}, but sets the value for the <em>target</em> member on the Message returned.
    * @param h  Handler to assign to the returned Message object's <em>target</em> member.
    * @return A Message object from the global pool.
    */
  public static Message obtain(Handler h) {
     Message m = obtain();
     m.target = h;
     return m;
  }
  ...
}
  • 其中Message.target是一個(gè)Handler類型的成員變量拙已。為啥Message要記錄構(gòu)造它的Handler對(duì)象决记? 好問(wèn)題!但這個(gè)問(wèn)題的解答需要等到分析消息處理的時(shí)候才能解答倍踪,先留個(gè)懸念系宫。
  • 構(gòu)造消息調(diào)用鏈的終點(diǎn)是Message.obtain(),源碼如下:
public final class Message implements Parcelable {
    //省略了非關(guān)鍵代碼
    ...
    // sometimes we store linked lists of these things
    //指向消息鏈上下一個(gè)消息的引用
    /*package*/ Message next;

    //消息鏈頭部引用建车,它是靜態(tài)的扩借,可以被所有消息對(duì)象共享
    private static Message sPool;
    //消息鏈長(zhǎng)度
    private static int sPoolSize = 0;

    ...
    /**
     * Return a new Message instance from the global pool. Allows us to
     * avoid allocating new objects in many cases.
     */
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                //1. 定義指向消息鏈頭部引用
                Message m = sPool;
                //2. 定義新的消息鏈頭部
                sPool = m.next;
                //3. 斷鏈
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                //返回消息鏈頭部消息
                return m;
            }
        }
        //如果消息鏈為空則新建消息
        return new Message();
    }
    ...
}
  • 如果對(duì)數(shù)據(jù)結(jié)構(gòu)中的鏈表還有映像,obtain()就是在取鏈表頭缤至。圖示如下:
    1
2
3
  • 消息池是用鏈表結(jié)構(gòu)實(shí)現(xiàn)的潮罪。那 Message一定有一個(gè)指向后續(xù)結(jié)點(diǎn)的“指針”,果不其然领斥,在其成員變量中找到Message next;嫉到。
  • 消息池頭指針sPool是一個(gè)Message類型的靜態(tài)變量,這表示所有Message都共享這一個(gè)消息池月洛。
  • obtain()是從消息池中拿消息何恶,那一定還有一個(gè)方法是往池里填消息,在Message類中搜索sPool使用的地方嚼黔,找到如下這個(gè)方法:
    /**
     * Recycles a Message that may be in-use.
     * Used internally by the MessageQueue and Looper when disposing of queued Messages.
     */
    void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        //清理消息攜帶的數(shù)據(jù)
        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) {
            //限制消息池大小
            if (sPoolSize < MAX_POOL_SIZE) {
                //1. 回收的消息接入消息鏈
                next = sPool;
                //2. 回收的消息成為消息鏈新頭部
                sPool = this;
                sPoolSize++;
            }
        }
    }
  • 正如猜想的那樣recycleUnchecked()會(huì)將當(dāng)前消息插入到消息鏈頭部细层。圖示如下
    1
2
  • 讀到這里,我們知道“消息從池中來(lái)最終又回到池中去”隔崎,那到底消息是在什么時(shí)候才會(huì)被回收到消息池呢今艺? 好問(wèn)題韵丑!這個(gè)問(wèn)題要等分析完消息分發(fā)才能解答爵卒。但現(xiàn)在我們可以大膽的猜測(cè)一下:承載壽司的碟子會(huì)在壽司被享用完之后被廚房回收,那消息是不是再被處理完之后就被回收了撵彻?

總結(jié)


Android消息機(jī)制中的“構(gòu)造消息”部分講完了钓株,總結(jié)一下:消息的生命周期會(huì)經(jīng)歷“創(chuàng)建-回收-再利用”,所有消息共享一個(gè)鏈表結(jié)構(gòu)的消息池陌僵,它用于存放被回收的消息轴合。

故事還沒(méi)有結(jié)束,下一篇會(huì)繼續(xù)講解分發(fā)消息

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末碗短,一起剝皮案震驚了整個(gè)濱河市受葛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖总滩,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纲堵,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡闰渔,警方通過(guò)查閱死者的電腦和手機(jī)席函,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)冈涧,“玉大人茂附,你說(shuō)我怎么就攤上這事《焦” “怎么了营曼?”我有些...
    開(kāi)封第一講書人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)愚隧。 經(jīng)常有香客問(wèn)我溶推,道長(zhǎng),這世上最難降的妖魔是什么奸攻? 我笑而不...
    開(kāi)封第一講書人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任蒜危,我火速辦了婚禮,結(jié)果婚禮上睹耐,老公的妹妹穿的比我還像新娘辐赞。我一直安慰自己,他們只是感情好硝训,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布响委。 她就那樣靜靜地躺著,像睡著了一般窖梁。 火紅的嫁衣襯著肌膚如雪赘风。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 52,158評(píng)論 1 308
  • 那天纵刘,我揣著相機(jī)與錄音邀窃,去河邊找鬼。 笑死假哎,一個(gè)胖子當(dāng)著我的面吹牛瞬捕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播舵抹,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼肪虎,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了惧蛹?” 一聲冷哼從身側(cè)響起扇救,我...
    開(kāi)封第一講書人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤刑枝,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后迅腔,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體仅讽,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年钾挟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了洁灵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡掺出,死狀恐怖徽千,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情汤锨,我是刑警寧澤双抽,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布,位于F島的核電站闲礼,受9級(jí)特大地震影響牍汹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜柬泽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一慎菲、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧锨并,春花似錦露该、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至包警,卻和暖如春撵摆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背害晦。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工特铝, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人篱瞎。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓苟呐,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親俐筋。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

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