天天看點

Handler 系列二:如何通信

承接上一篇handler系列一,上篇主要總結了handler如何通信,這篇來介紹handler怎麼通信。

handler的通信機制

handler,looper,messagequeue如何關聯

Handler 系列二:如何通信

建立handler,并采用目前線程的looper建立消息循環系統;

handler通過sendmessage(message)或post(runnable)發送消息,調用enqueuemessage把消息插入到消息連結清單中;

looper循環檢測消息隊列中的消息,若有消息則取出該消息,并調用該消息持有的handler的dispatchmessage方法,回調到建立handler線程中重寫的handlemessage裡執行。

handler及其關聯的類圖

Handler 系列二:如何通信

以上類圖可以快速幫助我們理清handler與looper、messagequeue的關系,以下從源碼的角度慢慢分析:

上一段很熟悉的代碼:

從sendmessagequeue開始追蹤,函數調用關系:sendmessage -> sendmessagedelayed ->sendmessageattime,在sendmessageattime中,攜帶者傳來的message與handler的mqueue一起通過enqueuemessage進入隊列了。

對于postrunnable而言,通過post投遞該runnable,調用getpostmessage,通過該runnable構造一個message,再通過 sendmessagedelayed投遞,接下來和sendmessage的流程一樣了。

在enqueuemessage中,通過messagequeue入隊列,并為該message的target指派為目前的handler對象,記住<code>msg.target</code>很重要,之後looper取出該消息時,還需要由<code>msg.target.dispatchmessage</code>回調到該handler中處理消息。

在messagequeue中,由message的消息連結清單進行入隊列

構造looper時,建構消息循環隊列,并擷取目前線程

但該函數是私有的,外界不能直接構造一個looper,而是通過looper.prepare來構造的:

這裡建立looper,并把looper對象儲存在sthreadlocal中,那sthreadlocal是什麼呢?

static final threadlocal sthreadlocal = new threadlocal();

theadlocal 如何儲存與擷取looper?

在<code>loop</code>中,一個循環,通過<code>next</code>取出messagequeue中的消息

若取出的消息為null,則結束循環,傳回。

設定消息為空,可以通過messagequeue的quit和quitsafely方法通知消息隊列退出。

若取出的消息不為空,則通過msg.target.dispatchmessage回調到handler中去。

looper把消息回調到handler的dispatchmessage中進行消息處理:

若該消息有callback,即通過post(runnable)的方式投遞消息,因為在投遞<code>runnable</code>時,把<code>runnable</code>對象指派給了message的<code>callback</code>。

若handler的mcallback不為空,則交由通過<code>callback</code>建立handler方式去處理。

否則,由最常見建立handler對象的方式,在重寫handlermessage中處理。

以一個時序圖來總結handler的消息機制,包含上述如何關聯looper和messagequeue的過程。

handler-looper-messagequeue時序圖

Handler 系列二:如何通信

繼續閱讀