Android面試 Handler機(jī)制

面試問(wèn)題

  • 什么是Handler
  • Handler的組成部分
  • 一個(gè)線(xiàn)程有幾個(gè)Handler双饥?
  • 一個(gè)線(xiàn)程有幾個(gè)Looper损姜?如何保證洋机?
  • Handler內(nèi)存泄漏的原因?為什么其它的內(nèi)部類(lèi)沒(méi)有說(shuō)過(guò)這個(gè)問(wèn)題曾掂?
  • 如果想在子線(xiàn)程new Handler要做哪些準(zhǔn)備?
  • 子線(xiàn)程中維護(hù)的Looper壁顶,消息隊(duì)列無(wú)消息的時(shí)候的處理方案是什么珠洗?有什么用?
  • 既然可以存在多個(gè)Handler往MessageQueue中添加數(shù)據(jù)(發(fā)消息Handler可能在不同線(xiàn)程)若专,那它內(nèi)部是如何保證線(xiàn)程安全的许蓖?
  • 我們使用Message時(shí)應(yīng)該如何創(chuàng)建它?
  • Looper死循環(huán)為什么不會(huì)導(dǎo)致程序卡死调衰?

什么是Handler

Handler就是解決線(xiàn)程與線(xiàn)程間的通信膊爪。
當(dāng)我們?cè)谧泳€(xiàn)程處理耗時(shí)操作,耗時(shí)操作完成后我們需要更新UI的時(shí)候嚎莉,這就是需要使用Handler來(lái)處理了米酬,因?yàn)樽泳€(xiàn)程不能更 新UI,Handler能讓我們?nèi)菀椎陌讶蝿?wù)切換回來(lái)它所在的線(xiàn)程趋箩。
消息處理機(jī)制本質(zhì):一個(gè)線(xiàn)程開(kāi)啟循環(huán)模式持續(xù)監(jiān)聽(tīng)并依次處理其他線(xiàn)程給它發(fā)的消息赃额。

Handler的組成部分

  • Message:message就是用來(lái)線(xiàn)程直接的交互數(shù)據(jù)琼懊,可以攜帶少量數(shù)據(jù),它有四個(gè)常用的字段 1.what 2.age1 3.age2, 4.obj
    what爬早,age1哼丈,age2可以攜帶整行數(shù)據(jù),obj呢就可以是任意類(lèi)型筛严。
  • Handler:handler呢就是用來(lái)發(fā)送消息和處理消息的醉旦,發(fā)送消息我們一般使用的都是Send和Post方法這個(gè)系列的方法,而這個(gè)Post一系列方法是通過(guò)Send一系列方法來(lái)實(shí)現(xiàn)的桨啃,而send的這些方法最后都是通過(guò)SendMessageAtTime()方法來(lái)實(shí)現(xiàn)的车胡,Handler發(fā)送一條消息,就在消息隊(duì)列中插一條消息照瘾。
  • Message Queue:消息隊(duì)列的意思匈棘,它主要用于存放所有通過(guò)Handler發(fā)送的消息,這部分消息會(huì)一直存儲(chǔ)在消息隊(duì)列中析命,等待被處理主卫,每個(gè)線(xiàn)程里面只能有一個(gè)Message Queue對(duì)象。
    MessageQueue的鹃愤,它的底層是通過(guò)單鏈表的數(shù)據(jù)結(jié)構(gòu)來(lái)維護(hù)消息列表的簇搅,它有兩個(gè)方法 enQueueMessage()和next()
    enQueueMessage()主要根據(jù)時(shí)間的順序向單鏈表中插入一條消息,next方法是一個(gè)無(wú)限循環(huán)的方法软吐,如果有消息返回這條消息瘩将,并從鏈表中移除,如果沒(méi)有消息的話(huà)凹耙,就一直阻塞在這里
  • Looper:每個(gè)線(xiàn)程通過(guò)Handler發(fā)送的消息都保存在MessageQueue中姿现,Looper通過(guò)Loop()的方法就去進(jìn)入一個(gè)無(wú)限循環(huán)當(dāng)中,然后每當(dāng)發(fā)現(xiàn)MessageQueue中存在一條消息肖抱,就會(huì)將它取出來(lái)备典,并傳遞到Handler的handlermessage()方法中,每個(gè)線(xiàn)程只能有一個(gè)Looper對(duì)象虐沥。
    Looper在這個(gè)循環(huán)中不斷的從messageQueue的next方法中獲取消息熊经,而next方法是一個(gè)阻塞操作,沒(méi)有消息的時(shí)候一直處于阻塞狀態(tài)欲险,當(dāng)有消息了通過(guò)dspatchMessage()發(fā)送消息給Handler對(duì)象
  • Theradlcal:messageQueue對(duì)象和Looper對(duì)象在每個(gè)線(xiàn)程中都只會(huì)有一個(gè)對(duì)象镐依,怎么來(lái)保證它有一個(gè)對(duì)象,就通過(guò)Threadlocal來(lái)保存天试,Threadlocal是一個(gè)線(xiàn)程內(nèi)部的數(shù)據(jù)存儲(chǔ)類(lèi)槐壳,通過(guò)它可以在指定的線(xiàn)程中存儲(chǔ)數(shù)據(jù),數(shù)據(jù)存儲(chǔ)以后只能在指定線(xiàn)程中可以獲取到存儲(chǔ)的數(shù)據(jù)喜每,對(duì)于其他的線(xiàn)程來(lái)說(shuō)則無(wú)法獲取到數(shù)據(jù)务唐。

一個(gè)線(xiàn)程有幾個(gè)Handler

一個(gè)線(xiàn)程可以有多個(gè)Handler雳攘,通過(guò)new Handler的方式創(chuàng)建。

一個(gè)線(xiàn)程有幾個(gè)Looper枫笛,如何保證

一個(gè)線(xiàn)程只能有一個(gè)Looper吨灭,通過(guò)Looper.perpare方法會(huì)創(chuàng)建一個(gè)Looper保存在ThreadLocal中,每個(gè)線(xiàn)程都有一個(gè)LocalThreadMap刑巧,會(huì)將Looper保存在對(duì)應(yīng)線(xiàn)程中的LocalThreadMap喧兄,key為T(mén)hreadLocal,value為L(zhǎng)ooper啊楚。

Handler內(nèi)存泄漏的原因吠冤,為什么其它的內(nèi)部類(lèi)沒(méi)有說(shuō)過(guò)這個(gè)問(wèn)題

內(nèi)部類(lèi)持有外部類(lèi)的對(duì)象,handler持有activity的對(duì)象恭理,當(dāng)頁(yè)面activity關(guān)閉時(shí)拯辙,handler還在發(fā)送消息,handler持有activity的對(duì)象颜价,導(dǎo)致handler不能及時(shí)被回收涯保,所以造成內(nèi)存泄漏。

因?yàn)楫?dāng)handler發(fā)送消息時(shí)拍嵌,會(huì)有耗時(shí)操作遭赂,并且會(huì)利用線(xiàn)程中的looper和messageQueue進(jìn)行消息發(fā)送,looper和messageQueue的生命周期是很長(zhǎng)的横辆,和application一樣,所以handler不容易被銷(xiāo)毀茄猫,所以造成內(nèi)存泄漏狈蚤。

解決方案有:

  • 把handler生命成靜態(tài)內(nèi)部類(lèi),靜態(tài)內(nèi)部類(lèi)不會(huì)持有activity划纽,所以不會(huì)造成內(nèi)存泄漏脆侮,
  • 弱引用(WeakReference):把使用handle的activity設(shè)置成弱引用,

如果想在子線(xiàn)程new Handler要做哪些準(zhǔn)備

可以在子線(xiàn)程中創(chuàng)建Handler勇劣,我們需要調(diào)用Looper.perpare和Looper.loop方法靖避。或者通過(guò)獲取主線(xiàn)程的looper來(lái)創(chuàng)建Handler比默。

子線(xiàn)程中維護(hù)的Looper幻捏,消息隊(duì)列無(wú)消息的時(shí)候的處理方案是什么

應(yīng)該調(diào)用Looper的quit方法,因?yàn)榭梢詫ooper中的messageQueue里的message都移除掉命咐,并且將內(nèi)存釋放篡九。

Handler如何保證線(xiàn)程安全

通過(guò)synchronized鎖機(jī)制保證線(xiàn)程安全。

我們使用Message時(shí)應(yīng)該如何創(chuàng)建它

Message.obtain來(lái)創(chuàng)建Message醋奠。這樣會(huì)復(fù)用之前的Message的內(nèi)存榛臼,不會(huì)頻繁的創(chuàng)建對(duì)象伊佃,導(dǎo)致內(nèi)存抖動(dòng)。

Looper死循環(huán)為什么不會(huì)導(dǎo)致程序卡死

  1. 導(dǎo)致應(yīng)用卡死的原因只有一下幾種情況:
  • 輸入事件在5秒內(nèi)未響應(yīng)沛善;
  • 在主線(xiàn)程執(zhí)行耗時(shí)操作航揉;
  1. Looper.loop()函數(shù)會(huì)在死循環(huán)里不斷的去獲取messagequeue里的message,當(dāng)消息隊(duì)列里沒(méi)有消息的時(shí)候金刁,looper會(huì)進(jìn)入休眠階段迷捧。Looper為了防止message執(zhí)行過(guò)于耗時(shí)的操作,導(dǎo)致隊(duì)列阻塞胀葱,就給message設(shè)置一個(gè)ANR的狀態(tài)漠秋。可見(jiàn)抵屿,looper的死循環(huán)和應(yīng)用卡死是兩個(gè)不同的概念庆锦。

點(diǎn)擊頁(yè)面上的按鈕后更新TextView的內(nèi)容,談?wù)勀愕睦斫?/h3>

點(diǎn)擊按鈕的時(shí)候會(huì)發(fā)送消息到Handler轧葛,但是為了保證優(yōu)先執(zhí)行搂抒,會(huì)加一個(gè)標(biāo)記異步,同時(shí)會(huì)發(fā)送一個(gè)target為null的消息尿扯,這樣在使用消息隊(duì)列的next獲取消息的時(shí)候求晶,如果發(fā)現(xiàn)消息的target為null,那么會(huì)遍歷消息隊(duì)列將有異步標(biāo)記的消息獲取出來(lái)優(yōu)先執(zhí)行衷笋,執(zhí)行完之后會(huì)將target為null的消息移除芳杏。(同步屏障)

更多內(nèi)容戳這里(整理好的各種文集)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市辟宗,隨后出現(xiàn)的幾起案子爵赵,更是在濱河造成了極大的恐慌,老刑警劉巖泊脐,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件空幻,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡容客,警方通過(guò)查閱死者的電腦和手機(jī)秕铛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)缩挑,“玉大人但两,你說(shuō)我怎么就攤上這事〉骷澹” “怎么了镜遣?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我悲关,道長(zhǎng)谎僻,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任寓辱,我火速辦了婚禮艘绍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘秫筏。我一直安慰自己诱鞠,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布这敬。 她就那樣靜靜地躺著航夺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪崔涂。 梳的紋絲不亂的頭發(fā)上阳掐,一...
    開(kāi)封第一講書(shū)人閱讀 51,692評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音冷蚂,去河邊找鬼缭保。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蝙茶,可吹牛的內(nèi)容都是我干的艺骂。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼隆夯,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼钳恕!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起吮廉,我...
    開(kāi)封第一講書(shū)人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤苞尝,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后宦芦,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡轴脐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年调卑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片大咱。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡恬涧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出碴巾,到底是詐尸還是另有隱情溯捆,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布厦瓢,位于F島的核電站提揍,受9級(jí)特大地震影響啤月,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜劳跃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一谎仲、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧刨仑,春花似錦郑诺、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至轻抱,卻和暖如春飞涂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背十拣。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工封拧, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人夭问。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓泽西,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親缰趋。 傳聞我的和親對(duì)象是個(gè)殘疾皇子捧杉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

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