讀Android Handler相關(guān)源碼

因?yàn)樽罱鼫?zhǔn)備面試,被問(wèn)到源碼相關(guān)的問(wèn)題,沒能回答上來(lái),再加上之前就有想要讀源碼的想法,趁著現(xiàn)在比較閑,開始這個(gè)讀源碼系列。

開始

android framework里handler相關(guān)源碼是比較少,作為入門很合適。handler源碼下載或在線閱讀的地址,google一下就能找到,這里就不贅述了。
先找到handler源碼,一開始的類注釋很詳細(xì),先讀一遍對(duì)于理解源碼有幫助,并且引出了message和message queue這兩個(gè)相關(guān)類。接著讓我們關(guān)注handler的多個(gè)重載的構(gòu)造方法。這些構(gòu)造方法的最終目的,都是賦值類變量mLooper,mQueue,mCallback,mAsynchronous,其中mLooper和mQueue是為了在handler中提供方法實(shí)現(xiàn)發(fā)生、取消消息以方便調(diào)用而不需要讓客戶端代碼深入到looper和message queue中,callback是包含handleMessage方法的接口,以避免必須繼承handler才能使用的限制,而mAsynchronous是為了使handler實(shí)現(xiàn)異步發(fā)生消息,設(shè)置此值的構(gòu)造器設(shè)置為了hide,需要通過(guò)靜態(tài)方法createAsync()創(chuàng)建。
handler發(fā)送的消息的參數(shù)分為兩種,一種是Runnable,一種是message,不過(guò)Runnable參數(shù)的方法,實(shí)現(xiàn)里也是先通過(guò)obtain方法獲取一個(gè)message,再將message的callback設(shè)置為這個(gè)runnable,所以最終實(shí)現(xiàn)也是發(fā)送message參數(shù)。接著我們來(lái)看message的實(shí)現(xiàn)。
message類封裝了消息的描述(what)和數(shù)據(jù)(包含兩個(gè)int類型的arg以提供低開銷的存儲(chǔ),如果夠用的話,或者可以使用setData)。message的obtain方法實(shí)現(xiàn)了message的復(fù)用,其原理是,首先在message中定義靜態(tài)字段sPool,在message的recycleUnchecked方法中,將當(dāng)前message賦值給sPool,然后obtain方法實(shí)現(xiàn)就可以檢查sPool是否為null,不是的話就可以將這個(gè)對(duì)象返回,以減少對(duì)象創(chuàng)建的消耗。當(dāng)然只有sPool的話,就只能復(fù)用一個(gè)message,所以message對(duì)象中還有next字段,實(shí)現(xiàn)一個(gè)鏈表結(jié)構(gòu),在recycleUnchecked方法中,將sPool賦值給next,第一次調(diào)用時(shí),sPool為null,如果此時(shí)第二次調(diào)用,因?yàn)閟Pool已經(jīng)被賦值了,所以next就指向第一次調(diào)用時(shí)的sPool,而sPool就指向了當(dāng)前的message,然后在obtain方法中,在將當(dāng)前sPool賦值給要返回的message對(duì)象之后,將sPool的next賦值給sPool,以將鏈表的頭指向下一個(gè)未被使用的message。
了解了message的實(shí)現(xiàn)之后,我們終于可以看一下發(fā)送和取消message的實(shí)現(xiàn)。這涉及到MessageQueue和Looper這兩個(gè)類。首先是發(fā)送,調(diào)用handler的sendMessage或者postRunnable之類的方法,最終都會(huì)調(diào)用到MessageQueue的enqueueMessage方法,這個(gè)方法用到了MessageQueue內(nèi)部維護(hù)的mMessages對(duì)象,如果這個(gè)對(duì)象為null,則直接將要發(fā)送的消息賦值給這個(gè)mMessages,否則就又用到了我們之前提到的Message的next內(nèi)部字段,插入的邏輯則不是絕對(duì)的頭插或者尾插,而是根據(jù)message的when字段(涉及到延遲處理消息的邏輯),將這個(gè)新的消息插入到鏈表中。而取消message,根據(jù)調(diào)用的方法不同,具體的實(shí)現(xiàn)也會(huì)有一些差異,但基本的邏輯都是先得到第一個(gè)message,順著next字段遍歷鏈表,找到滿足條件(包含跟給定的字段相等的字段)的message,調(diào)用其recycle方法(最終就是之前講的recycleUnchecked方法)將這個(gè)message邏輯狀態(tài)改為可復(fù)用。
接著發(fā)送message之后講,消息是在哪里得到處理的呢,這就涉及到Looper了。Looper是用來(lái)在線程中啟動(dòng)一個(gè)消息循環(huán),構(gòu)造方法中會(huì)創(chuàng)建一個(gè)MessageQueue。先調(diào)用Looper的prepare方法,以初始化,然后調(diào)用loop方法開啟循環(huán),至于將這兩步拆分成兩個(gè)方法,則是為了在loop開啟循環(huán)之前,有機(jī)會(huì)創(chuàng)建關(guān)聯(lián)這個(gè)looper的handler,然后再啟動(dòng)循環(huán)。
然后就是關(guān)鍵的loop方法,方法實(shí)現(xiàn)中有一部分是為了打印,記錄日志,關(guān)鍵的邏輯代碼就是在一個(gè)for循環(huán)中,調(diào)用MessageQueue的next方法,而這個(gè)方法,就將我們剛才賦值的mMessages對(duì)象返回用于處理,當(dāng)然實(shí)際的方法實(shí)現(xiàn)沒這么簡(jiǎn)單,會(huì)涉及到message因?yàn)樵O(shè)置了延時(shí),而時(shí)間沒有到,則設(shè)置到設(shè)置的延時(shí)時(shí)間再處理,而且在得到要返回的message對(duì)象之后,需要將這個(gè)對(duì)象的next字段指向的對(duì)象賦值給mMessage用于下一次處理。在得到了待處理的message對(duì)象之后,調(diào)用message對(duì)象的target字段(此字段是Handler類型)上的dispatchMessage方法,進(jìn)行處理。這個(gè)方法先判斷message自己的callback字段是否為null,不是的話,調(diào)用callback的run方法,否則如果handler自己的mCallback字段是否為Null,不是的話,調(diào)用其handleMessage方法,否則的話就調(diào)用handler自己的handleMessage方法。
有幾點(diǎn)自己看的不是很明白,首先在MessageQueue中,涉及到很多別的native方法,在next方法中就有調(diào)用nativePollOnce本地方法,目前還沒有看過(guò)其實(shí)現(xiàn),然后就是message有異步消息和同步消息的區(qū)別,源碼注釋中有提到,同步消息會(huì)受到barrier的限制,比如ui更新的時(shí)候,就會(huì)阻塞消息的處理,但異步消息不受此限制,這些地方還需要查找資料加以理解。
寫了這么多,就是簡(jiǎn)單的梳理了一下自己一天讀源碼的思路,有不妥之處,歡迎指出。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容