
前言:Handler機制應(yīng)該是網(wǎng)上講解最多的一種機制(沒有之一),本篇用通俗易懂的語言來介紹一下Handler機制,讓大家可以更好的理解。
什么是Handler機制?
Handler機制是AndroidSDK提供的一個非常重要的處理異步消息的機制,主要是由Handler、Looper、Message和MessageQueue組成,Handler只是消息處理機制的一部分。
- Message:消息(分為硬件產(chǎn)生的消息和軟件產(chǎn)生的消息)。
- MessageQueue:消息隊列,主要是向消息池投遞消息(MessageQueue.enqueueMessage)和取走消息池中的消息(MessageQueue.next)。
- Handler:主要功能是向消息池發(fā)送消息(Handler.sendMessage)和處理消息(Handler.handleMessage)。
- Looper:不停的循環(huán)執(zhí)行(Looper.loop),從MessageQueue中取出Message并發(fā)送給Handler。
分析上述各部分:
Message:什么是硬件消息和軟件消息呢?硬件消息就是我們滑動觸摸點擊按鈕等等,軟件消息就是我們主動new Message發(fā)送出去的。Message實現(xiàn)了Parcelable接口封裝消息數(shù)據(jù),所以他是存在于內(nèi)存中的。一個實體(類)如果需要封裝到消息中去就必須實現(xiàn)這一接口。
MessageQueue:相當(dāng)于一個容器,消息池。上述看到了.next應(yīng)該猜到是鏈表形式,實際上確實是單鏈表維護,在插入和刪除上有優(yōu)勢。在其next()中會無限循環(huán),不斷的判斷是否有消息,有就返回這條消息并移除。
Looper:Looper創(chuàng)建的時候會創(chuàng)建一個MessageQueue,它們兩個是一一對應(yīng)的關(guān)系。調(diào)用Looper.loop()的時候消息循環(huán)開始,不斷地調(diào)用MessageQueue的next()方法,當(dāng)有消息就處理,否則就堵塞在next()方法中。loop()跟MessageQueue的next()一樣都是死循環(huán)(源碼可見for(;;))。退出時調(diào)用Looper.quit(),它會調(diào)用MessageQueue的quit()方法,此時next會返回null,然后loop()方法也跟著退出。
Handler:在主線程構(gòu)造Handler,new Handler()里調(diào)用了Looper.myLooper()這個方法,這個方法是獲取當(dāng)前線程的Looper的。在其他線程調(diào)用sendMessage()時主線程的MessageQueue會插入一條Message,然后被Looper使用,在Looper的loop()中通過回調(diào) msg.target.dispatchMessage(msg);發(fā)送給Handler。Handler跟Looper的關(guān)系是多對一。

解釋完各部分的分工那來總結(jié)一下他們之間的關(guān)系:Handler負責(zé)發(fā)送消息(Message)到MessageQueue中,Looper負責(zé)循環(huán)的接收MessageQueue中的消息通過回調(diào)方法返還給Handler自己本身。

容易忽略的Message,使用時應(yīng)注意的地方有哪些?
Message在Handler機制中看似很不起眼,但至關(guān)重要。它封裝了任務(wù)攜帶的信息和該任務(wù)的handler,使用時應(yīng)注意:
- Message可以通過 new 來獲取,但通常使用Message.obtain()或Handler.obtainMessage()方法來從消息池中獲取空消息對象,可以節(jié)省資源!
- 如果Message只需要攜帶簡單的int型數(shù)據(jù),優(yōu)先使用arg1和arg2來傳遞數(shù)據(jù),比Bundle節(jié)省內(nèi)存。
- 使用Message.what來標(biāo)識信息便于處理Message。
- 最后如果需要從工作線程返回很多數(shù)據(jù)信息再借助Bundle對象將數(shù)據(jù)集中到一起放在obj屬性中,返回到主線程處理。
Looper源碼簡述:
上面說了那么多Looper的方法,但在Activity中使用Handler時沒看到過Looper的影子啊,原來Activity內(nèi)部包含了一個Looper對象,它會自動管理Looper并處理子線程中發(fā)送過來的消息。前面說到過,初始化Handler時在Handler的構(gòu)造函數(shù)中會把當(dāng)前線程的Looper與Handler關(guān)聯(lián),所以在Activity中無需顯式的使用Looper。


源碼簡述
網(wǎng)上介紹Handler機制的文章解釋最詳細的就是Looper,會附帶源碼每一篇都會解釋的很透徹。這里就簡單的總結(jié)一下Looper,詳細請去查閱Looper源碼。


那什么是TheadLocal呢?
ThrealLocal 是一個泛型類。
工作原理:ThreadLocal存儲數(shù)據(jù)時先獲取當(dāng)前線程,然后通過當(dāng)前線程來創(chuàng)建Values,如果沒有Values就new一個Values實例。然后存儲傳進來的Value。獲取的時候也是根據(jù)當(dāng)前線程的Values來獲取的。
它的get()和set()方法如下圖:


最后說一下為什么Handler機制會造成內(nèi)存泄露
因為非靜態(tài)內(nèi)部類導(dǎo)致的!
我們知道非靜態(tài)內(nèi)部類默認就會持有外部類的引用,當(dāng)非靜態(tài)內(nèi)部類對象的生命周期比外部類還長就會導(dǎo)致內(nèi)存泄露。

上面介紹Message時說過mHandler會作為成員變量保存在發(fā)送的消息msg中,所以msg就會持有mHandler的引用,而mHandle是MainActivity的非靜態(tài)內(nèi)部類實例,所以mHandler就持有MainActivity的引用。msg間接持有MainActivity的引用。msg發(fā)送到消息隊列(MessageQueue)中等待Looper輪詢處理。當(dāng)MainActivity退出后,msg可能還存在消息隊列中未處理或正在處理。這樣就會導(dǎo)致MainActivity無法被回收,以致發(fā)生MainActivity的內(nèi)存泄露。
解決辦法:使用靜態(tài)內(nèi)部類+弱引用的方式


結(jié)束
到此Handler機制的內(nèi)容就算講完了,但本篇只是用比較容易理解的方式介紹了一下Handler機制,Handler機制在Android開發(fā)中隨處可見也很重要。大家很有必要去深入研究一下,去看一下里面的源碼或結(jié)合一些講解源碼的文章自己理解一下。希望能幫到大家,有錯的地方請?zhí)岢鰜砉?/p>