HandlerThread的詳解

—诀艰、Looper , Handler , Message之間的關(guān)系
Looper負(fù)責(zé)的就是創(chuàng)建一個MessageQueue吼旧,然后進(jìn)入一個無限循環(huán)體不斷從MessageQueue中讀取消息毡惜,而消息的創(chuàng)建者就是一個或多個Handler 澎埠。若消息隊(duì)列為空捣炬,線程則會阻塞等待浇揩。
1.Looper


Paste_Image.png

sThreadLocal是一個ThreadLocal對象仪壮,可以在一個線程中存儲變量「旎眨可以看到积锅,在第78行,將一個Looper的實(shí)例放入了ThreadLocal养盗,并且75-77行判斷了sThreadLocal是否為null缚陷,否則拋出異常。這也就說明了Looper.prepare()方法不能被調(diào)用兩次往核,同時也保證了一個線程中只有一個Looper實(shí)例

Paste_Image.png

在構(gòu)造方法中箫爷,創(chuàng)建了一個MessageQueue(消息隊(duì)列)。

Paste_Image.png

方法直接返回了sThreadLocal存儲的Looper實(shí)例聂儒,如果me為null則拋出異常虎锚,也就是說looper方法必須在prepare方法之后運(yùn)行。
第114行:拿到該looper實(shí)例中的mQueue(消息隊(duì)列)
121到153行:就進(jìn)入了我們所說的無限循環(huán)衩婚。
122行:取出一條消息窜护,如果沒有消息則阻塞。
135行:使用調(diào)用 msg.target.dispatchMessage(msg);把消息交給msg的target的dispatchMessage方法去處理非春。Msg的target是什么呢柄慰?其實(shí)就是handler對象鳍悠,下面會進(jìn)行分析。
152行:釋放消息占據(jù)的資源坐搔。
Looper主要作用:
1藏研、 與當(dāng)前線程綁定沃斤,保證一個線程只會有一個Looper實(shí)例钠乏,同時一個Looper實(shí)例也只有一個MessageQueue。
2化撕、 loop()方法凳忙,不斷從MessageQueue中去取消息业踏,交給消息的target屬性的dispatchMessage去處理。
好了涧卵,我們的異步消息處理線程已經(jīng)有了消息隊(duì)列(MessageQueue)勤家,也有了在無限循環(huán)體中取出消息的哥們,現(xiàn)在缺的就是發(fā)送消息的對象Handler了柳恐;

2伐脖、Handler
1、首先Looper.prepare()在本線程中保存一個Looper實(shí)例乐设,然后該實(shí)例中保存一個MessageQueue對象讼庇;因?yàn)長ooper.prepare()在一個線程中只能調(diào)用一次,所以MessageQueue在一個線程中只會存在一個近尚。
2蠕啄、Looper.loop()會讓當(dāng)前線程進(jìn)入一個無限循環(huán),不端從MessageQueue的實(shí)例中讀取消息戈锻,然后回調(diào)msg.target.dispatchMessage(msg)方法歼跟。
3、Handler的構(gòu)造方法格遭,會首先得到當(dāng)前線程中保存的Looper實(shí)例嘹承,進(jìn)而與Looper實(shí)例中的MessageQueue想關(guān)聯(lián)。
4如庭、Handler的sendMessage方法,會給msg的target賦值為handler自身撼港,然后加入MessageQueue中坪它。
5、在構(gòu)造Handler實(shí)例時帝牡,我們會重寫handleMessage方法往毡,也就是msg.target.dispatchMessage(msg)最終調(diào)用的方法。
3靶溜、HandlerThread
HandlerThread本質(zhì)上是一個線程類开瞭,繼承自Thread類懒震,但是HandlerThread有自己的Looper對象,可以進(jìn)行l(wèi)ooper循環(huán)嗤详,不斷從MessageQueue中取消息个扰。
可以看出,我們將前面的創(chuàng)建的HandlerThread實(shí)例的Looper對象傳遞給了Handler葱色,這使得該Handler擁有了HandlerThread的Looper對象递宅,通過該Handler發(fā)送的消息,都將被發(fā)送到該Looper對象的MessageQueue中苍狰,且回調(diào)方法的執(zhí)行也是執(zhí)行在HandlerThread這個異步線程中办龄。
值得注意的是,如果在handleMessage()執(zhí)行完成后淋昭,如果想要更新UI俐填,可以用UI線程的Handler發(fā)消息給UI線程來更新。

源碼角度解析HandlerThread
HandlerThread在run()方法中翔忽,執(zhí)行了Looper.prepare()方法英融,mLooper保存并獲得了當(dāng)前線程的Looper對象,并通過notifyAll()方法去喚醒等待線程呀打,最后執(zhí)行了Looper.loop()開啟looper循環(huán)語句矢赁。也就是說,run()方法的主要作用就是完成looper機(jī)制的創(chuàng)建贬丛。

Handler通過getLooper()方法獲取looper對象撩银。該方法首先判斷當(dāng)前線程是否啟動?如果沒有啟動,返回null豺憔;如果啟動额获,進(jìn)入同步語句。如果mLooper為null恭应,代表mLooper沒有被賦值抄邀,則當(dāng)前調(diào)用線程進(jìn)入等待階段。直到Looper對象被創(chuàng)建且通過notifyAll()方法喚醒等待線程昼榛,最后才會返回Looper對象境肾。我們看到在run()方法中,mLooper在得到Looper對象后胆屿,會發(fā)送notifyAll()方法來喚醒等待的線程奥喻。

Looper對象的創(chuàng)建在子線程的run()方法中執(zhí)行,但是調(diào)用getLooper()的地方是在主線程中運(yùn)行非迹,我們無法保證在調(diào)用getLooper()時Looper已經(jīng)被成功創(chuàng)建环鲤,所以會在getLooper()中存在一個同步的問題,通過等待喚醒機(jī)制解決了同步的問題

HandlerThread退出
無論是調(diào)用quit()方法還是quitSafely()憎兽,最終都將執(zhí)行到MessageQueue中的quit()方法冷离。
quit()方法最終執(zhí)行的removeAllMessagesLocked()方法吵冒,該方法主要是把MessageQueue消息池中所有的消息全部清空,無論是延遲消息(延遲消息是指通過sendMessageDelayed或通過postDelayed等方法發(fā)送)還是非延遲消息西剥。

quitSafely()方法痹栖,其最終執(zhí)行的是MessageQueue中的removeAllFutureMessagesLocked方法,該方法只會清空MessageQueue消息池中所有的延遲消息蔫耽,并將消息池中所有的非延遲消息派發(fā)出去讓Handler去處理完成后才停止Looper循環(huán)结耀,quitSafely相比于quit方法安全的原因在于清空消息之前會派發(fā)所有的非延遲消息。最后需要注意的是Looper的quit方法是基于API 1匙铡,而Looper的quitSafely方法則是基于API 18的图甜。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市鳖眼,隨后出現(xiàn)的幾起案子黑毅,更是在濱河造成了極大的恐慌,老刑警劉巖钦讳,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件矿瘦,死亡現(xiàn)場離奇詭異,居然都是意外死亡愿卒,警方通過查閱死者的電腦和手機(jī)缚去,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來琼开,“玉大人易结,你說我怎么就攤上這事」窈颍” “怎么了搞动?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長渣刷。 經(jīng)常有香客問我鹦肿,道長,這世上最難降的妖魔是什么辅柴? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任箩溃,我火速辦了婚禮,結(jié)果婚禮上碌嘀,老公的妹妹穿的比我還像新娘涣旨。我一直安慰自己,他們只是感情好筏餐,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著牡拇,像睡著了一般魁瞪。 火紅的嫁衣襯著肌膚如雪穆律。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天导俘,我揣著相機(jī)與錄音峦耘,去河邊找鬼。 笑死旅薄,一個胖子當(dāng)著我的面吹牛辅髓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播少梁,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼洛口,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了凯沪?” 一聲冷哼從身側(cè)響起第焰,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎妨马,沒想到半個月后挺举,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡烘跺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年湘纵,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片滤淳。...
    茶點(diǎn)故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡梧喷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出娇钱,到底是詐尸還是另有隱情伤柄,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布文搂,位于F島的核電站适刀,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏煤蹭。R本人自食惡果不足惜笔喉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望硝皂。 院中可真熱鬧常挚,春花似錦、人聲如沸稽物。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽贝或。三九已至吼过,卻和暖如春锐秦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背盗忱。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工酱床, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人趟佃。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓扇谣,卻偏偏與公主長得像,于是被迫代替她去往敵國和親闲昭。 傳聞我的和親對象是個殘疾皇子罐寨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評論 2 354

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