前言
Handler機制老生常談 也是面試必考 最近公司也在面試 發現很多人第三庫都會用 比如熟練運用okhttp,rxjava 但是偏偏Android裏面很重要的Handler機制卻說的模棱兩可,雖說代碼很多 但是流程並不複雜 這次讓我們站在源碼的角度去理解並掌握它
概念
Handler機制:主線程和子線程的通信機制 多用在子線程發送消息通知UI線程更新UI
Looper:輪詢器 AndroidThread中啓動 死循環 一直存在 直到進程銷燬
MessageQueue:Looper的成員變量 消息隊列 鏈表結構
Message:MessageQueue的成員變量 一個消息實體類
流程分析
既然說Handler用於在主線程和子線程傳遞消息的 這裏我們要把握一個關鍵點->消息隊列 有隊列就有入隊和出隊 自然構成了handler收發消息的整個流程,先來看看源碼方法的大概調用過程
- handler的sendMessage方法發出消息 通過 queue.enqueue方法進入MessageQueue(消息隊列)
- Looper的loop方法不停的從MessageQueue裏取消息
- 沒消息就阻塞 有消息的話Looper就會調用Message的handler對象的dispathchMessage方法轉發消息
- dispathchMessage方法裏面實際調用的handleMessage回調
源碼實現
Handler
首先是入口方法handler.sendMessage
分析:最終會調用queue.enqueueMessage方法 queue就是MessageQueue(消息隊列)
這裏的queue是怎麼來的呢? 看看Handler的構造函數
分析:實際上是Handler初始化的時候就賦了值,queue是Looper裏面的 而mLooper = Looper.myLooper 下面去Looper裏面看看這個方法
Looper
分析: Looper構造函數裏面初始化了MessageQueue,以及當前線程 myLooper方法這裏的sThreadLocal是什麼呢?再看
原來是Looper持有一個靜態的本地線程(ThreadLocal) 它是java爲解決多線程併發所提供的一種方法。簡單說就是數據隔離
用在這裏的意義在於->我們可能會有另一個主線程(有別於UI線程)收發消息 多個主線程應該持有自己的Looper對象 保證每個線程的數據隔離 互不干擾
深入理解可以看http://blog.csdn.net/lufeng20/article/details/24314381
問題又來了,我們知道獲取Looper對象是sTreadLocal.get() 也就是本地線程中取出來的,那麼是什麼時候放進去的呢?也就是說Looper是什麼開始構建出來 並工作的呢?
我知道沒有Looper輪詢器取消息 handler可以發消息 但絕b收不到消息 所以我們可以想的到 Looper很有可能是在UI進程一啓動 就創建了 我們去Android入口看看:
AndroidThread
分析:到這裏我們可以感到欣慰了,如果沒有猜錯的話 Looper.prepareMainLooper();就是構建Looper對象的方法
Looper
果然是這樣的 UI線程會創建一個Looper對象 並set到TreadLocal裏面 我們注意到prepare(false) UI線程這裏傳的是false 而其他線程默認是true 看下它是在那用到的 找到MessageQueue裏面的quit方法
MessageQueue
分析: MessageQueue裏面的quit 意思是消息沒有處理完 主動退出 而主線程是不予許你這樣操作的 所以傳的false
大致的我們都清楚了 最後看下Looper.loop()
總結
最後我們再把流程梳理一遍
AndroidTread ->Looper.prepareMainLooper() -> Looper.loop()
1. AndroidThread創建一個UI線程的Looper對象並set到ThreadLocal在Looper的構造函數裏會初始化當前MessageQueue對象和當前線程
2. handler.sendMessage最終調用當前Looper的MessageQueue對象的enqueueMessage方法將消息壓入消息隊列(MessageQueue)
3. Looper的loop方法先從ThreadLocal 取出當前線程的Looper對象,得到當前Looper對象的MessageQueue然後輪詢調用MessageQueue的next方法取消息
4. 如果有Message就調用這個Message的handler對象的dispatchMessage方法轉發消息
5. 最後在handleMessage回調接受消息
子線程裏面怎麼用Handler接收消息?
看到這裏我們知道 每個線程都有一個Looper對象去輪詢MessageQueue裏面的消息 然後轉發給handler接收 UI線程在AndroidThread裏面幫我們寫好了創建Looper以及Looper.loop的方法 那麼如果要在子線程中使用Handler 我們就需要手動創建 其實源碼註釋已經給瞭解釋
Android還給我們提供了HandlerThread這樣一個類 也是這種實現方式
最後
handler.sendMessage的時候 不是直接new Message而是用的 Message.obtain(),它的內部是一個緩存池 可以避免頻繁創建對象 節省內存
另外,MessageQueue enqueueMessage入隊方法 以及 next出隊方法的實現 這些涉及到鏈表數據結構
我這裏主要分析了java層的代碼 源碼裏面還用到很多native的方法 這些需要我們對Android底層C代碼有更深入的研究..