天天看點

【Android】簡單全面的了解Handler機制

【Android】簡單全面的了解Handler機制
前言:Handler機制應該是網上講解最多的一種機制(沒有之一),本篇用通俗易懂的語言來介紹一下Handler機制,讓大家可以更好的了解。

什麼是Handler機制?

Handler機制是AndroidSDK提供的一個非常重要的處理異步消息的機制,主要是由Handler、Looper、Message和MessageQueue組成,Handler隻是消息處理機制的一部分。

- Message:消息(分為硬體産生的消息和軟體産生的消息)。

- MessageQueue:消息隊列,主要是向消息池投遞消息(MessageQueue.enqueueMessage)和取走消息池中的消息(MessageQueue.next)。

- Handler:主要功能是向消息池發送消息(Handler.sendMessage)和處理消息(Handler.handleMessage)。

- Looper:不停的循環執行(Looper.loop),從MessageQueue中取出Message并發送給Handler。

分析上述各部分:

Message:什麼是硬體消息和軟體消息呢?硬體消息就是我們滑動觸摸點選按鈕等等,軟體消息就是我們主動new Message發送出去的。Message實作了Parcelable接口封裝消息資料,是以他是存在于記憶體中的。一個實體(類)如果需要封裝到消息中去就必須實作這一接口。

MessageQueue:相當于一個容器,消息池。上述看到了.next應該猜到是連結清單形式,實際上确實是單連結清單維護,在插入和删除上有優勢。在其next()中會無限循環,不斷的判斷是否有消息,有就傳回這條消息并移除。

Looper:Looper建立的時候會建立一個MessageQueue,它們兩個是一一對應的關系。調用Looper.loop()的時候消息循環開始,不斷地調用MessageQueue的next()方法,當有消息就處理,否則就堵塞在next()方法中。loop()跟MessageQueue的next()一樣都是死循環(源碼可見for(;;))。退出時調用Looper.quit(),它會調用MessageQueue的quit()方法,此時next會傳回null,然後loop()方法也跟着退出。

Handler:在主線程構造Handler,new Handler()裡調用了Looper.myLooper()這個方法,這個方法是擷取目前線程的Looper的。在其他線程調用sendMessage()時主線程的MessageQueue會插入一條Message,然後被Looper使用,在Looper的loop()中通過回調 msg.target.dispatchMessage(msg);發送給Handler。Handler跟Looper的關系是多對一。

一段Looper的源碼片段:

【Android】簡單全面的了解Handler機制

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

【Android】簡單全面的了解Handler機制

容易忽略的Message,使用時應注意的地方有哪些?

Message在Handler機制中看似很不起眼,但至關重要。它封裝了任務攜帶的資訊和該任務的handler,使用時應注意:

- Message可以通過 new 來擷取,但通常使用Message.obtain()或Handler.obtainMessage()方法來從消息池中擷取空消息對象,可以節省資源!

- 如果Message隻需要攜帶簡單的int型資料,優先使用arg1和arg2來傳遞資料,比Bundle節省記憶體。

- 使用Message.what來辨別資訊便于處理Message。

- 最後如果需要從工作線程傳回很多資料資訊再借助Bundle對象将資料集中到一起放在obj屬性中,傳回到主線程處理。

Looper源碼簡述:

上面說了那麼多Looper的方法,但在Activity中使用Handler時沒看到過Looper的影子啊,原來Activity内部包含了一個Looper對象,它會自動管理Looper并處理子線程中發送過來的消息。前面說到過,初始化Handler時在Handler的構造函數中會把目前線程的Looper與Handler關聯,是以在Activity中無需顯式的使用Looper。

【Android】簡單全面的了解Handler機制

但在子線程中則需要我們自己維護Looper。

【Android】簡單全面的了解Handler機制
【Android】簡單全面的了解Handler機制
源碼簡述

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

【Android】簡單全面的了解Handler機制

可以看出Prepare()的工作方式核心就是将Looperd對象定義為ThreadLocal,将唯一的Looper對象添加到ThreadLocal中。

【Android】簡單全面的了解Handler機制

Looper在構造方法中建立了一個MessageQueue和目前線程Thread。

那什麼是TheadLocal呢?

ThrealLocal 是一個泛型類。

工作原理:ThreadLocal存儲資料時先擷取目前線程,然後通過目前線程來建立Values,如果沒有Values就new一個Values執行個體。然後存儲傳進來的Value。擷取的時候也是根據目前線程的Values來擷取的。

它的get()和set()方法如下圖:

【Android】簡單全面的了解Handler機制
【Android】簡單全面的了解Handler機制

使用場景:資料是以線程為作用域并且不同線程具有不同的資料副本時可以使用。

最後說一下為什麼Handler機制會造成記憶體洩露

因為非靜态内部類導緻的!

我們知道非靜态内部類預設就會持有外部類的引用,當非靜态内部類對象的生命周期比外部類還長就會導緻記憶體洩露。

【Android】簡單全面的了解Handler機制

上面介紹Message時說過mHandler會作為成員變量儲存在發送的消息msg中,是以msg就會持有mHandler的引用,而mHandle是MainActivity的非靜态内部類執行個體,是以mHandler就持有MainActivity的引用。msg間接持有MainActivity的引用。msg發送到消息隊列(MessageQueue)中等待Looper輪詢處理。當MainActivity退出後,msg可能還存在消息隊列中未處理或正在處理。這樣就會導緻MainActivity無法被回收,以緻發生MainActivity的記憶體洩露。

解決辦法:使用靜态内部類+弱引用的方式

【Android】簡單全面的了解Handler機制

mHandler通過弱引用的方式持有MainActivity,當GC執行垃圾回收時遇到MainActivity就會回收并釋放所占的記憶體單元,避免記憶體洩露。msg還可能存在MessageQueue中,是以在MainActivity銷毀時将mHandler的回調和發送的消息給移除掉。

【Android】簡單全面的了解Handler機制

結束

到此Handler機制的内容就算講完了,但本篇隻是用比較容易了解的方式介紹了一下Handler機制,Handler機制在Android開發中随處可見也很重要。大家很有必要去深入研究一下,去看一下裡面的源碼或結合一些講解源碼的文章自己了解一下。希望能幫到大家,有錯的地方請提出。