面试:Handler 的工作原理是怎样的?
面試場景
平時開發(fā)用到其他線程嗎?都是如何處理的?
基本都用 RxJava 的線程調(diào)度切換,嗯對,就是那個?observeOn?和?subscribeOn?可以直接處理,比如網(wǎng)絡(luò)操作,RxJava 提供了一個叫?io?線程的處理。
在 RxJava 的廣泛使用之前,有使用過其他操作方式嗎?比如 Handler 什么的?
當(dāng)然用過呀。
那你講講 Handler 的工作原理吧。
Handler 工作流程基本包括 Handler、Looper、Message、MessageQueue 四個部分。但我們在日常開發(fā)中,經(jīng)常都只會用到 Handler 和 Message 兩個類。Message 負(fù)責(zé)消息的搭載,里面有個?target?用于標(biāo)記消息,obj?用于存放內(nèi)容,Handler 負(fù)責(zé)消息的分發(fā)和處理。
一般在開發(fā)中是怎么使用 Handler 的?
官方不允許在子線程中更新 UI,所以我們經(jīng)常會把需要更新 UI 的消息直接發(fā)給處理器 Handler,通過重寫 Handler 的?handleMessage()?方法進(jìn)行 UI 的相關(guān)操作。
那使用中就沒什么需要注意的嗎?
有,Handler 如果設(shè)置為私有變量的話,Android Studio 會報警告,提示可能會造成內(nèi)存泄漏,這種情況可以通過設(shè)置為靜態(tài)內(nèi)部類 + 弱引用,或者在?onDestroy()?方法中調(diào)用?Handler.removeCallbacksAndMessages(null)?即可避免;
正文
總的來說這位面試的童鞋答的其實還是沒那么差,不過細(xì)節(jié)程度還不夠,所以南塵就來帶大家一起走進(jìn) Handler。
Handler 工作流程淺析
異步通信準(zhǔn)備 => 消息入隊 => 消息循環(huán) => 消息處理
異步通信準(zhǔn)備
假定是在主線程創(chuàng)建 Handler,則會直接在主線程中創(chuàng)建處理器對象?Looper、消息隊列對象?MessageQueue?和 Handler 對象。需要注意的是,Looper?和?MessageQueue?均是屬于其?創(chuàng)建線程?的。Looper?對象的創(chuàng)建一般通過?Looper.prepareMainLooper()?和?Looper.prepare()?兩個方法,而創(chuàng)建?Looper?對象的同時,將會自動創(chuàng)建?MessageQueue,創(chuàng)建好?MessageQueue?后,Looper?將自動進(jìn)入消息循環(huán)。此時,Handler?自動綁定了主線程的?Looper?和?MessageQueue。
消息入隊
工作線程通過?Handler?發(fā)送消息?Message?到消息隊列?MessageQueue?中,消息內(nèi)容一般是 UI 操作。發(fā)送消息一般都是通過?Handler.sendMessage(Message msg)?和?Handler.post(Runnabe r)?兩個方法來進(jìn)行的。而入隊一般是通過?MessageQueue.enqueueeMessage(Message msg,long when)?來處理。
消息循環(huán)
主要分為「消息出隊」和「消息分發(fā)」兩個步驟,Looper?會通過循環(huán)?取出?消息隊列?MessageQueue?里面的消息?Message,并?分發(fā)?到創(chuàng)建該消息的處理者?Handler。如果消息循環(huán)過程中,消息隊列?MessageQueue?為空隊列的話,則線程阻塞。
消息處理
Handler?接收到?Looper?發(fā)來的消息,開始進(jìn)行處理。
對于 Handler ,一些需要注意的地方
- 1 個線程?Thread?只能綁定 1個循環(huán)器?Looper,但可以有多個處理者?Handler
- 1 個循環(huán)器?Looper?可綁定多個處理者?Handler
- 1 個處理者?Handler?只能綁定 1 個 1 個循環(huán)器?Looper
常規(guī)情況下,這些相關(guān)對象是怎么創(chuàng)建的?
前面我們說到?Looper?是通過?Looper.prepare()?和?Looper.prepareMainLooer()?創(chuàng)建的,我們不妨看看源碼里面到底做了什么。
我們不得不看看?Looper?的構(gòu)造方法都做了什么。
顯而易見,確實在創(chuàng)建了?Looper?對象的時候,自動創(chuàng)建了消息隊列對象?MessageQueue。
而?Looper.prepareMainLooper()?從名稱也很容易看出來,是直接在主線程內(nèi)創(chuàng)建對象了。而在我們?nèi)粘i_發(fā)中,經(jīng)常都是在主線程使用?Handler,所以導(dǎo)致了很少用到?Looper.prepare()?方法。
而生成?Looper?和?MessageQueue?對象后,則自動進(jìn)入消息循環(huán):Looper.loop(),我們不妨再看看里面到底做了什么?
截圖中的代碼比較簡單,大家應(yīng)該不難看懂,我們再看看如何通過?MessageQueue.next()來取消息設(shè)置阻塞狀態(tài)的。
我們?nèi)∠⒉捎昧艘粋€無限 for 循環(huán),當(dāng)沒有消息的時候,則把標(biāo)記位?nextPollTimeOutMillis?設(shè)置為 -1,在進(jìn)行下一次循環(huán)的時候,通過?nativePollOnce()?直接讓其處于線程阻塞狀態(tài)。
再看看我們的消息分發(fā)是怎么處理的,主要看上面的?msg.target.dispatchMessage(msg)?方法。
原來?msg.target?返回的是一個?Handler?對象,我們直接看看?Handler.dipatchMessage(Message msg)?做了什么。
總結(jié):
- 在主線程中?Looper?對象自動生成,無需手動生成。而在子線程中,一定要調(diào)用Looper.prepare()?創(chuàng)建?Looper?對象。如果在子線程不手動創(chuàng)建,則無法生成?Handler?對象。
- 分發(fā)消息給?Handler?的過程為:根據(jù)出隊消息的歸屬者,通過?dispatchMessage(msg)?進(jìn)行分發(fā),最終回調(diào)復(fù)寫的?handleMessage(Message msg)。
- 在消息分發(fā)?dispatchMessage(msg)?方法中,會進(jìn)行 1 次發(fā)送方式判斷:
1. 若?msg.callback?屬性為空,則代表使用了?post(Runnable r)?發(fā)送消息,則直接回調(diào)?Runnable?對象里面復(fù)寫的?run()。
2. 若?msg.callback?屬性不為空,則代表使用了?sendMessage(Message msg)?發(fā)送消息,直接回調(diào)復(fù)寫的?handleMessage(msg)。
常規(guī)的消息 Message 是如何創(chuàng)建的?
我們經(jīng)常會在?Handler?的使用中創(chuàng)建消息對象?Message,創(chuàng)建方式也有兩個?new Message()?或者?Message.obtain()。我們通常都更青睞于?Message.obtain()?這種方式,因為這樣的方式,可以有效避免重復(fù)創(chuàng)建?Message?對象。實際上在代碼中也是顯而易見的。
Handler 的另外一種使用方式
前面主要講解了?Handler.sendMessage(Message msg)?這種常規(guī)使用方式,實際上,我們有時候也會用?Handler.post(Runnable r)?進(jìn)行處理,我們當(dāng)然應(yīng)該看看里面是怎么處理的。
從官方注釋可以看到,這會直接將?Runnable?對象加到消息隊列中,我們來看看 `getPostMessage(r) 到底做了什么。
我們上面的分析是對的。在?getPostMessage(Runnable r)?方法中,我們除了通過?Message.obtain()?方法來創(chuàng)建消息對象外,專門把?Runnable?對象賦值給了?callback,這樣才用了上面做消息分發(fā)的時候,通過這個標(biāo)記來判斷是用的?post()?還是?sendMessage()?方式。
到底是如何發(fā)消息的?
一直在說通過?sendMessage()?方式來發(fā)消息,到底這個消息是怎么發(fā)送的呢?
?
直接看?sendMessageAtTime()。
enqueueMessage()?里面做了什么?
至此,你大概明白了兩種方式的區(qū)別了。
寫在最后
本次內(nèi)容可能講的比較多和亂,還望大家跟著到源碼中一步一步分析,最困難的時候,就是提升最大的時候!
轉(zhuǎn)載于:https://www.cnblogs.com/liushilin/p/8667917.html
總結(jié)
以上是生活随笔為你收集整理的面试:Handler 的工作原理是怎样的?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C#中Equals和==的比较
- 下一篇: BZOJ3572 [Hnoi2014]世