消息機制
Android 消息機制是 Android 系統(tǒng)運行的基礎(chǔ)伤柄,主要涉及到 Looper、MessageQueue、Handler 等類茁影。
-
Looper
- Looper 是消息循環(huán)的根據(jù)地;
- 它在 prepare 方法中利用 ThreadLocal 將 Looper 與當(dāng)前線程進行綁定丧凤,Handler 初始化時會對當(dāng)前線程進行判斷募闲,如果不是 Looper 線程,那就會拋出異常愿待;
- 一個 Looper 與一個 MessageQueue 進行唯一綁定浩螺,消息循環(huán)實際上是由 MessageQueue 實現(xiàn)的:無限循環(huán)調(diào)用 MessageQueue 的 next 方法,如果有消息就通過 Handler#target 屬性回調(diào)處理仍侥,如果沒有就阻塞(真正的阻塞也在 next 方法里)要出;
-
MessageQueue
Message 的存儲容器,以 Message.when 進行排序农渊。名為消息隊列患蹂,實際數(shù)據(jù)結(jié)構(gòu)為鏈表,因為鏈表在插入和讀取上有較大優(yōu)勢砸紊,而頻繁插入讀取正是消息機制的應(yīng)用場景传于。
-
Handler
在構(gòu)造方法中校驗當(dāng)前線程是否為 Looper 線程;可顯示指定 Looper 對象醉顽,指定的 Looper 對象即為消息處理的目標線程沼溜;
內(nèi)部的 MessageQueue 對象實際上來自于 Looper 持有的引用,調(diào)用 enqueueMessage 方法將消息入隊時游添,會通過 target 屬性將當(dāng)前 Handler 與當(dāng)前 Message 綁定系草,方便之后處理具體的消息時,能夠讓某個消息找到目標 Handler 對象唆涝;(同一線程可以有多個 Handler找都,不同 Handler 發(fā)送的消息可以被發(fā)送它們的 Handler 正確處理)
-
最后處理 Message 時是在 Looper 中調(diào)用 dispatchMessage 方法:
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
由上面的代碼也可以看出優(yōu)先級:
- 如果有 callback,那就不會執(zhí)行 handleMessage 方法石抡;
- 如果是在聲明 Handler 時檐嚣,從構(gòu)造器傳入了 Callback 對象,并且該方法返回 true,那就不會再回調(diào) handleMessage 方法嚎京;如果返回了 false嗡贺,那就會繼續(xù)回調(diào)到 handleMessage 方法;
系統(tǒng)層對 Handler 的應(yīng)用
介紹完消息機制的基本概念和原理后鞍帝,下面說一下系統(tǒng)級別對 Handler 機制的應(yīng)用诫睬。
我們知道 App 的啟動入口在 ActivityThread 的 main 方法中。
- 當(dāng)這個方法執(zhí)行時帕涌,會調(diào)用
Looper.prepareMainLooper()
方法摄凡,從而將當(dāng)前線程轉(zhuǎn)換為唯一的 UI 線程并構(gòu)建 ActivityThread 實例; - 之后調(diào)用 attach 方法蚓曼,在這個方法中會創(chuàng)建 Binder 通道亲澡,獲取到 AMS 對象,與 system_server 建立連接纫版;
- 開啟 Looper 循環(huán)床绪;
在與 system_server 建立連接后,ActivityThread 與 ActivityManagerService 進行通信其弊,ActivityThread 以 IActivityManager 為媒介操作 AMS癞己,AMS 以 IApplicationThread 為媒介操作 ActivityThread,在 Binder 線程與 UI 線程之間進行交互梭伐。
在 attach 方法執(zhí)行過程中痹雅,AMS 最終會回調(diào)到 ApplicationThread 的 bindApplication 方法中:
public final void bindApplication(){
sendMessage(H.BIND_APPLICATION, data);
}
緊接著,UI 線程會使用之前聲明 Handler 對象 mH糊识,開啟系統(tǒng)層的 Handler 消息處理的旅途绩社。