Handler 源碼分析

?????為了深入了解Handler翘骂,我們對Handler進(jìn)行源碼分析壁熄,看看它究竟是如何完成線程間通信的。

從Handler構(gòu)造出發(fā)

?????既然是源碼分析碳竟,為什么突然回到Handler的構(gòu)造了呢草丧?在我的Handler使用機(jī)制及四個(gè)組成部分文章中,當(dāng)我們在非主線程創(chuàng)建handler對象時(shí)會(huì)出現(xiàn)一個(gè)異常莹桅。如下:

05-30 15:26:07.490 711-773/com.perry.handler E/AndroidRuntime: FATAL EXCEPTION: Thread-18868
                                                               Process: com.perry.handler, PID: 711
                                                               java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
                                                                   at android.os.Handler.<init>(Handler.java:209)
                                                                   at android.os.Handler.<init>(Handler.java:123)
                                                                   at com.perry.handler.OnBackgroundActivity$2.run(OnBackgroundActivity.java:71)
                                                                   at java.lang.Thread.run(Thread.java:818)

?????出現(xiàn)這個(gè)問題實(shí)際上是因?yàn)椴矗琱andler需要Looper對象烛亦,來進(jìn)行內(nèi)部的全局變量的初始化。


Handler 構(gòu)造函數(shù).png
public Handler(Callback callback, boolean async)
public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

?????通過查看源碼發(fā)現(xiàn)懂拾,handler共7個(gè)構(gòu)造函數(shù)煤禽,使用時(shí)只能使用4個(gè),最后都會(huì)調(diào)用執(zhí)行如上2個(gè)構(gòu)造方法岖赋,而這2個(gè)構(gòu)造方法大同小異檬果,所以我們挑個(gè)簡短的來看看。發(fā)現(xiàn)handler需要looper對象來初始化全局變量Looper及MessageQueue唐断,而MessageQueue是從looper中取出的选脊。MessageQueue用于進(jìn)程間傳遞消息,Looper則在該線程內(nèi)進(jìn)行消息的派發(fā)脸甘。

handler.sendMessage

?????我們通過構(gòu)造找到了handler的2個(gè)協(xié)同者恳啥,Looper與MessageQueue。那我們發(fā)個(gè)消息丹诀,看看他們都做了些什么6鄣摹?
?????無論調(diào)用post方法還是sendMessage方法铆遭,handler都會(huì)從上到下依次調(diào)用如下方法硝桩。

sendMessageDelayed(Message msg, long delayMillis)
sendMessageAtTime(Message msg, long uptimeMillis)
enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)

handler.enqueueMessage

?????此時(shí),到了enqueueMessage方法疚脐,就證明這條消息確實(shí)發(fā)送了亿柑,該做下一步處理。

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

?????該方法中對message設(shè)置了target棍弄,將當(dāng)前的handler存于message中,用于之后message找到自己該去的handler疟游,而后將massage交給MessageQueue呼畸。調(diào)用queue.enqueueMessage(msg, uptimeMillis)方法,將消息放入到消息隊(duì)列中颁虐。強(qiáng)調(diào)一下蛮原,這里的queue就是我們前面說到的在構(gòu)造方法中從looper中取到的消息隊(duì)列。

Looper.loop()

?????到了這里另绩,我們發(fā)現(xiàn)handler將消息通過MessageQueue放入到消息隊(duì)列中儒陨,那誰把消息取出來進(jìn)行派發(fā)的呢?草叢三兄弟笋籽,跳出來兩個(gè)了蹦漠,還剩Looper一人默默的蹲在那,那我們來看看他究竟干了啥车海?笛园!

public static void loop() {
        final Looper me = myLooper();
        final MessageQueue queue = me.mQueue;
        for (;;) {
            Message msg = queue.next(); // might block 取出消息爷狈,無消息則阻塞
            if (msg == null) {
                // No message indicates that the message queue is quitting. 沒有消息則表明,消息隊(duì)列正在退出辫呻。
                return;   
            }
            msg.target.dispatchMessage(msg); // 發(fā)送消息劳较, 其中target就是我們之前存入的Handler
        }
    }

?????精簡了一下該方法,可以看到棵红,Looper通過loop方法凶赁,不停的從MessageQueue中取出消息,最終調(diào)用了handler的dispatchMessage(msg)方法將消息派發(fā)給handler自己逆甜。

handler.dispatchMessage

?????最后哟冬,消息派發(fā)給handler,會(huì)先判斷msg的callback對象(實(shí)際上是runnable對象)是否為空忆绰,如果不為空則執(zhí)行handleCallback(msg)方法浩峡,callback.run();而如果為空就會(huì)調(diào)用handleMessage方法,完成回調(diào)错敢。(這也是為什么我們構(gòu)造Handler時(shí)翰灾,實(shí)現(xiàn)了抽象方法handleMessage而post(runnable)時(shí),為什么不調(diào)用handleMessage方法的原因)稚茅。

// msg.callback實(shí)際上是Runnable對象
// mCallback是一個(gè)實(shí)現(xiàn)了handleMessage(msg)的回調(diào)接口
public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg); // msg.callback.run();
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

?????那么來畫個(gè)圖總結(jié)一下纸淮。

Handler 源碼分析圖示.png

?????圖中我們從主線程中創(chuàng)建Handler,在子線程中發(fā)送消息亚享,而這一系列的配合操作咽块,需要仔細(xì)看圖,不懂的可以回看文章欺税。
?????上一篇:Handler使用機(jī)制及四個(gè)組成部分

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末侈沪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子晚凿,更是在濱河造成了極大的恐慌亭罪,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件歼秽,死亡現(xiàn)場離奇詭異应役,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)燥筷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門箩祥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人肆氓,你說我怎么就攤上這事袍祖。” “怎么了做院?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵盲泛,是天一觀的道長濒持。 經(jīng)常有香客問我,道長寺滚,這世上最難降的妖魔是什么柑营? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮村视,結(jié)果婚禮上官套,老公的妹妹穿的比我還像新娘。我一直安慰自己蚁孔,他們只是感情好奶赔,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著杠氢,像睡著了一般站刑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鼻百,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天绞旅,我揣著相機(jī)與錄音,去河邊找鬼温艇。 笑死因悲,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的勺爱。 我是一名探鬼主播晃琳,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼琐鲁!你這毒婦竟也來了卫旱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬榮一對情侶失蹤绣否,失蹤者是張志新(化名)和其女友劉穎誊涯,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蒜撮,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年跪呈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了段磨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡耗绿,死狀恐怖苹支,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情误阻,我是刑警寧澤债蜜,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布晴埂,位于F島的核電站,受9級(jí)特大地震影響寻定,放射性物質(zhì)發(fā)生泄漏儒洛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一狼速、第九天 我趴在偏房一處隱蔽的房頂上張望琅锻。 院中可真熱鬧,春花似錦向胡、人聲如沸恼蓬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽处硬。三九已至,卻和暖如春拇派,著一層夾襖步出監(jiān)牢的瞬間荷辕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來泰國打工攀痊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留桐腌,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓苟径,卻偏偏與公主長得像案站,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子棘街,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

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

  • Handler 已經(jīng)被無數(shù)人分析過了 為什么這里還要寫篇博文分析呢蟆盐,因?yàn)槟鞘莿e人的,自己分析的才是你自己的 han...
    簡書取名好難閱讀 249評(píng)論 0 0
  • Handler機(jī)制算是個(gè)老生常談的問題了遭殉,最近又看了下源碼石挂,決定還是形成文字記錄下來靠譜。 1险污、handler h...
    sankemao閱讀 250評(píng)論 0 2
  • 前言 在Android開發(fā)的多線程應(yīng)用場景中痹愚,Handler機(jī)制十分常用 今天,我將手把手帶你深入分析Handle...
    BrotherChen閱讀 474評(píng)論 0 0
  • 【Android Handler 消息機(jī)制】 前言 在Android開發(fā)中蛔糯,我們都知道不能在主線程中執(zhí)行耗時(shí)的任務(wù)...
    Rtia閱讀 4,843評(píng)論 1 28
  • https://wiki.sankuai.com/pages/viewpage.action?pageId=390...
    ztzt123閱讀 309評(píng)論 0 0