handler源碼分析

版本不同源碼不同;handler的作用是線程之間的通信,不僅僅是更新UI;

消息的入隊(duì):Handler.sendMessage->queue.euqueueMessage通過底層c++native層來實(shí)現(xiàn)的

出隊(duì):Looper.loop->(MessageQueue) queuq.next

MessageQueue方法里有一個(gè)next方法有一個(gè)for循環(huán),循環(huán)里面去不斷拿消息(message),然后再返回消息

Looper輪循器里面有一個(gè)loop方法會(huì)不斷的調(diào)用queue.next方法,也是在死循環(huán)里面

取出消息之后,再去轉(zhuǎn)發(fā)(Message msg=queue,next();在try,catch里面msg.target(Handler).dispatchMessage(msg));然后調(diào)用handleMessage();

handler發(fā)送一個(gè)消息會(huì)加到消息隊(duì)列里面,然后Looper不斷的從消息隊(duì)列里面取出消息,又去調(diào)用handler的distchMessage方法傳遞消息,distchMessage又調(diào)用handleMessage()方法并傳入消息;

Looper輪循器總是按照先進(jìn)先出的原則取出我們的消息

在子線程發(fā)送handler消息,結(jié)果在主線程接收到的原理:因?yàn)長ooper對(duì)象是在主線程調(diào)用的;????? 為什么handler發(fā)送消息要經(jīng)過一圈再自己接收?如果handler發(fā)送消息不經(jīng)過target可能需要再寫一個(gè)類(可能是抽象類);

loop方法里有一個(gè)死循環(huán)為什么在ActivityTreader里面調(diào)用不卡線程?因?yàn)閘oop是最后一個(gè)執(zhí)行的,前面的應(yīng)用創(chuàng)建都啟動(dòng)完成了,

Handler里面有一個(gè)mLooper=Looper.myLooper(); mQueue=mLooper.mQueue;

loop里面會(huì)調(diào)用myLooper方法里面有一個(gè)sThreadLocal.get();返回的是Looper對(duì)象

在prepare方法里面sThreadLocal.set(new Looper(quitAllowed)); set里面創(chuàng)建了一個(gè)Looper對(duì)象

存入Looper對(duì)象->prepare->sThreadLocal.set,獲取Looper對(duì)象->loop->myLooper->sThreadLocal.get

sThreadLocal是保證數(shù)據(jù)的隔離的,線程和線程之間數(shù)據(jù)不會(huì)影響,是一個(gè)map結(jié)構(gòu)通過key和value來保存數(shù)據(jù),A線程set進(jìn)去的數(shù)據(jù),通過get獲取的是A線程的數(shù)據(jù);會(huì)有多個(gè)線程來操作ThreadLocal,每個(gè)線程都有自己的Looper對(duì)象,

ActivityThread啟動(dòng)的時(shí)候回調(diào)用main方法,在main方法里會(huì)調(diào)用prepare方法創(chuàng)建Looper對(duì)象;在我們啟動(dòng)應(yīng)用程序的時(shí)候就會(huì)執(zhí)行Looper.loop();方法里面有一個(gè)for循環(huán)會(huì)不斷的拿到消息隊(duì)列里面的消息,looper里面有一個(gè)MessageQueue

一個(gè)線程只能有一個(gè)Looper對(duì)象,在prepare方法里首先判斷sThreadLocal中是否已經(jīng)存在Looper了,如果還沒有則創(chuàng)建一個(gè)新的Looper設(shè)置進(jìn)去。這樣也就完全解釋了為什么我們要先調(diào)用Looper.prepare()方法,才能創(chuàng)建Handler對(duì)象。同時(shí)也可以看出每個(gè)線程中最多只會(huì)有一個(gè)Looper對(duì)象。

調(diào)用Looper前一定要先執(zhí)行prepare,如果不執(zhí)行prepare方法(mLooper = Looper.myLooper();)loop方法里會(huì)獲得一個(gè)空的Looper對(duì)象,然后在判斷如果是空的就拋出一個(gè)異常,Looper里面有一個(gè)消息隊(duì)列;

myLooper方法里返回一個(gè)sThreadLocal.get();也就是獲取到的Looper對(duì)象;

主線程不需要手動(dòng)的去調(diào)用Looper.prepare();因?yàn)锳ctivity啟動(dòng)應(yīng)用的時(shí)候,在ActivityThread里面有個(gè)main方法在里面已經(jīng)通過Looper.prepareMainLooper();方法調(diào)用了,因?yàn)閜repareMainLooper()方法里有一個(gè)prepare(false);然后就會(huì)調(diào)用有參的prepare方法(有兩個(gè)prepare方法一個(gè)無參返回,一個(gè)有參有參的里面可以創(chuàng)建Looper對(duì)象);


MessageQueue是一個(gè)消息隊(duì)列,他可以把存入的消息以隊(duì)列的形式進(jìn)行排列,并提供入隊(duì)和出隊(duì)的方法。這個(gè)類是在Looper的構(gòu)造函數(shù)中創(chuàng)建的,因此一個(gè)Looper也就對(duì)應(yīng)了一個(gè)MessageQueue。

- 在worker線程中,如果直接創(chuàng)建handler會(huì)拋出運(yùn)行時(shí)異常-即通過查‘線程-value’映射表發(fā)現(xiàn)當(dāng)前線程無looper對(duì)象。所以需要先調(diào)用Looper.prepare()方法。在prepare方法里,利用ThreadLocal對(duì)象為當(dāng)前線程創(chuàng)建一個(gè)Looper(利用了一個(gè)Values類,即一個(gè)Map映射表,專為thread存儲(chǔ)value,此處為當(dāng)前thread存儲(chǔ)一個(gè)looper對(duì)象)。然后繼續(xù)創(chuàng)建handler,讓handler內(nèi)部的消息隊(duì)列指向該looper的消息隊(duì)列(這個(gè)很重要,讓handler指向looper里的消息隊(duì)列,即二者共享同一個(gè)消息隊(duì)列,然后handler向這個(gè)消息隊(duì)列發(fā)送消息,looper從這個(gè)消息隊(duì)列獲取消息)。然后looper循環(huán)消息隊(duì)列即可。當(dāng)獲取到message消息,會(huì)找出message對(duì)象里的target,即原始發(fā)送handler,從而回調(diào)handler的handleMessage() 方法進(jìn)行處理。

1、Handler為什么能夠?qū)崿F(xiàn)不同線程的通信?核心點(diǎn)在哪?

不同線程之間,每個(gè)線程擁有自己的Handler、消息隊(duì)列和Looper。Handler是公共的,線程可以通過使用目標(biāo)線程的Handler對(duì)象來發(fā)送消息,這個(gè)消息會(huì)自動(dòng)發(fā)送到所屬線程的消息隊(duì)列中去,線程自帶的Looper對(duì)象會(huì)不斷循環(huán)從里面取出消息并把消息發(fā)送給Handler,回調(diào)自身Handler的handlerMessage方法,從而實(shí)現(xiàn)了消息的線程間傳遞。

2、Handler的核心是一種事件激活式(類似傳遞一個(gè)中斷)的還是主要是用于傳遞大量數(shù)據(jù)的?重點(diǎn)在Message的內(nèi)容,偏向于數(shù)據(jù)傳輸還是事件傳輸。

目前的理解,它所依賴的是消息隊(duì)列,發(fā)送的自然是消息,即類似事件中斷。

它的簡單邏輯就是如果當(dāng)前MessageQueue中存在mMessages(即待處理消息),就將這個(gè)消息出隊(duì),然后讓下一條消息成為mMessages,否則就進(jìn)入一個(gè)阻塞狀態(tài),一直等到有新的消息入隊(duì)。

子線程中更新UI的方法:

1、Handler的post方法;

在post方法里返回一個(gè)發(fā)送消息的方法(也就是sendMessageDelayed(getPostMessage(r),0)),方法里面有一個(gè)getPostMessage()方法里面有一個(gè)Runnable對(duì)象參數(shù),后面還有個(gè)延時(shí)時(shí)間參數(shù)默認(rèn)為0;在getPostMessage()方法里面得到了一個(gè)Message對(duì)象,m.callback = r;Message對(duì)象調(diào)用callback,這個(gè)callback在Handler的dispathMessage()方法中做了個(gè)判斷,如果Message的callback等于null才會(huì)去調(diào)用handleMessage()方法,否則就調(diào)用handleCallback()方法。

也太簡單了!竟然就是直接調(diào)用了一開始傳入的Runnable對(duì)象的run()方法。

2、View的post()方法

原來就是調(diào)用了Handler中的post()方法,我相信已經(jīng)沒有什么必要再做解釋了。

3、Activity的runOnUiThread()方法

如果當(dāng)前的線程不等于UI線程(主線程),就去調(diào)用Handler的post()方法,否則就直接調(diào)用Runnable對(duì)象的run()方法。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容