Android Handler機制源碼解析

Android Handler機制源碼解析。

Android 規定對於修改界面UI的操作必須放在主線程中執行,而對於一些查詢數據庫或者聯網請求數據的耗時操作,為瞭避免產生界面暫時無響應等ANR的情況要放到子線程中進行。耗時操作完成後我們要切換到主線程去修改UI,涉及到線程間的通訊,這時候handler機制就派上用場瞭。

Handler機制的組成部分

Handler機制由四部分組成:Handler,Message,MessageQueue(消息隊列),Looper(輪詢器)。

Handler:我把他稱為消息處理器,handler機制中的重中之重,他與Looper相互協作,通過對MessageQueue進行消息的存取,從而達到線程間的通訊。可以說Handler想要正常的工作就必須有相對應的Looper輪詢器,如果新創建Handler所在的線程沒有looper對象,則會報錯”can’t creat handler inside thread that has not calledLooper.prepare()”,即無法再沒有調用Looper.prepare()方法的線程中創建Handler.而這一定在Handler的構造方法中也得以體現。

Looper:輪詢器,主要作用是維護MessageQueue,與Handler協作對消息隊列進行消息的存取。Looper的實例可以通過Looper.prepare()獲得。有一點必須要說明的是Looper本身是線程級別的,這裡貼出一段源碼可以看出來,sThreadLocal 是ThreadLocal的一個實例,它是一個線程級別的數據存儲類,從這裡可以看出Looper是線程級別的。

Message:消息,可以通過Message.obtain()方法獲得,message.what=..一般用於對該消息的編輯以便在handlerMessage時進行區分,而想要傳遞給主線程的數據可以通過message.obj=..來進行傳遞。

MessageQueue:消息隊列,為先進先出的線性隊列結構,Messagequeue本身是由looper維護的,在這裡貼一段Looper構造器源碼。

Handler機制的大概流程:

首先大概流程是:子線程耗時操作完畢後,將想要傳遞給主線程的數據存儲到Message對象或者將想要進行的操作封裝在Runable的run()方法中,然後通過Handler發送到消息隊列MessageQueue中。Loopper通過loop方法對消息隊列進行輪詢,該方法是個死循環,如果有消息隊列中有消息,就將該消息取出發送給發送該消息的handler,進而來處理該消息;如果消息隊列中沒有消息,則保持堵塞。

源碼分析:

首先從發送消息看起,我們知道Handler發送消息既可以sendMessage(Message msg),也可以通過post(Runablerun)來進行,

(1)先來看典型的sendMessage():

可以看到sendMessage()也是調用的sendMessageDelayed(),然後sendMessageDelayed()則調用sendMessageAtTime(),流程很簡單不多說。隨後走瞭enqueueMessage()方法,這個方法做瞭什麼呢?

(Handler中的equeueMessage()方法)

(MessageQueue的equeueMessage()方法)

可以看到是調用瞭MessageQueue的enqueueMessage()方法從而將消息添加到瞭消息隊列中。enqueueMessage()方法中有點需要註意的是在方法的最開始它對msg.target這個對象是否為空進行瞭判斷,如果為空則報錯,那麼msg.target到底是什麼呢?如果剛才你有仔細看Handler中enqueueMessage()方法的話,就會發現msg.target=this,而this即為Handler.這也是為消息打上一個標記,因為在後邊的流程中,msg會被傳遞到它所標記的handler中進行處理。

一切無誤,該Message就被加入瞭MessageQueue消息隊裡中,這時候我們該看看Looper是怎麼從MessageQueue中獲取消息然後分發的呢。

這就需要Looper的loop()方法瞭,可以看出他是個死循環,然後從他所維護的MessageQueue中輪詢獲取消息,沒有消息便保持阻塞狀態,有消息則調用msg.target.dispatchMessage()方法,從上面我們知道msg.target其實就是發送該消息的Handler,這時候我們看看dispatchMessage()方法都做瞭什麼。

我們暫且忽略msg.callback和mCallback這個判斷,後邊我們會提到,這時候則調用瞭handlerMessage()方法也就是我們在創建Handler對象時重寫的handlerMessage()方法。

(2)handler.post(Runable runable)

除瞭上邊說的通過handler的sendMessage()發送消息,我們也可以通過handler.post(runable)來發送個Runable接口對象。

可以看到該方法裡邊也是調用瞭sendMessageDelayed()方法,而第一個參數getPostMessage(r)則是將我們post 的Runable對象包裝成一個Message對象。

那麼上邊提到的Handler的dispathMessage()中的msg.callback也就是我們通過handler.post(runable)的runable對象瞭。而其中的handlerCallBack()無非就是調用runable中的run()方法瞭。

在上邊上邊提到的Handler的dispathMessage()中的mCallback其實是我們在創建Handler對象時傳入的CallBack接口對象,在Handler的構造方法中可以看到,這裡就不再說明瞭。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *