Handler,Looper,ThreadLocal的工作原理

Handler執(zhí)行流程

首先handler作為任務(wù)執(zhí)行者,一般創(chuàng)建在主線程,當(dāng)子線程有需要發(fā)送的數(shù)據(jù),通過(guò)創(chuàng)建message對(duì)象,使用handler對(duì)象將消息發(fā)送到messagequeue,messagequeue遵循了隊(duì)列先進(jìn)先出的原則,當(dāng)主線程的looper循環(huán)消息的時(shí)候,會(huì)按照messagequeue隊(duì)列的順序循環(huán)消息,并將消息給到任務(wù)執(zhí)行者h(yuǎn)andler去執(zhí)行任務(wù)。

Handler的作用以及工作原理

作用:因?yàn)樵贏ndroid中,主線程不建議做耗時(shí)的操作,子線程不建議更新UI,但是Android開發(fā),其實(shí)就是搭建好頁(yè)面,將服務(wù)器的數(shù)據(jù)展示到頁(yè)面上,所以使用網(wǎng)絡(luò)請(qǐng)求會(huì)非常頻繁,而網(wǎng)絡(luò)請(qǐng)求屬于耗時(shí)操作,需要放到子線程完成,但一般情況下也不會(huì)通過(guò)子線程更新UI,需要將請(qǐng)求成功的數(shù)據(jù)發(fā)送到主線程進(jìn)行UI更新,所以一般會(huì)使用到handler。

下面再來(lái)說(shuō)說(shuō)工作原理

工作原理:Handler創(chuàng)建完成后,內(nèi)部的Looper以及MessageQueue就可以和Handler一起協(xié)同工作,然后通過(guò)Hadler的post方法將一個(gè)Runnable投遞到Handler內(nèi)部的Looper中去處理,也可以通過(guò)Handler的send方法發(fā)送一個(gè)消息,這個(gè)消息會(huì)在Looper中做處理。Post最終也是通過(guò)send來(lái)完成的。當(dāng)Handler的send方法被調(diào)用時(shí),他會(huì)調(diào)用MessageQueue的enqueueMessage方法將這個(gè)消息放入消息隊(duì)列中,然后Looper發(fā)現(xiàn)有新消息到來(lái)時(shí),就會(huì)處理這個(gè)消息,最終消息中的Runnable或者Handler的handlerMessage方法就會(huì)被調(diào)用。Looper是運(yùn)行在Handler所在的線程,所以就把業(yè)務(wù)邏輯切換到主線程了。

ThreadLocal的工作原理

ThreadLocal的定義:ThreadLocal是線程內(nèi)部的數(shù)據(jù)存儲(chǔ)類,通過(guò)他可以在指定的線程中存儲(chǔ)數(shù)據(jù),該數(shù)據(jù)只有在指定線程中可以獲取。

ThreadLocal使用場(chǎng)景:當(dāng)某些數(shù)據(jù)是以線程為作用域,并且不同線程具有不同的數(shù)據(jù)副本的時(shí)候;另外還可以使用在復(fù)雜邏輯下的對(duì)象傳遞。比如監(jiān)聽器的傳遞 ,
ThreadLoal的值在table數(shù)組中的存儲(chǔ)位置總是為ThreadLocal的reference字段所標(biāo)識(shí)的對(duì)象的下一個(gè)位置。ThreasdLoacal的set和get方法所操作的對(duì)象都是當(dāng)前線程的localValues對(duì)象的table數(shù)組,因此在不同的線程中訪問同一個(gè)ThreadLocal的set和get方法,他們對(duì)ThreadLocal所做的讀寫操作僅限于各自線程的內(nèi)部,從而實(shí)現(xiàn)在多個(gè)線程中互不干擾的存儲(chǔ)和修改數(shù)據(jù)。

Looper的工作原理

Looper在Android的消息機(jī)制中扮演著消息循環(huán)的角色,就是不停的從MessageQueue中查看是否有新消息,如果有消息就立刻處理,否則就一直阻塞在那里,首先在構(gòu)造方法中創(chuàng)建一個(gè)MessageQueue即隊(duì)列消息,然后將當(dāng)前的對(duì)象保存起來(lái)。Looper除了prepare方法外,還提供了prepareMainLooper方法(這就是我們?cè)贛ainActivity里并沒有聲明Lopper),這個(gè)方法主要是給主線程也就是ActivityThread創(chuàng)建Looper使用的,其本質(zhì)也是通過(guò)prepare方法來(lái)實(shí)現(xiàn)的。由于主線程的Looper比較特殊,所以Looper提供了一個(gè)getMainLooper方法,通過(guò)它可以在任何地方獲取到主線程的Looper。

Looper的相關(guān)方法
Looper也是可以退出的,Looper提供了quit和quitSafely來(lái)退出一個(gè)Looper,二者的區(qū)別是:quit會(huì)直接退出Looper,而quieSafely只是假定一個(gè)特殊標(biāo)記,然后把消息隊(duì)列中的已有消息處理完畢后才安全退出。Looper退出后,通過(guò)Handler發(fā)送消息失敗,這個(gè)時(shí)候Handler的send方法會(huì)返回false。在子線程中,如果手動(dòng)為其創(chuàng)建Looper,那么在所有的事情完成以后應(yīng)該調(diào)用quit方法來(lái)終止消息循環(huán),否則這個(gè)子線程就會(huì)一直處于等待狀態(tài),而如果想退出Looper以后,這個(gè)線程就會(huì)立刻終止,因此建議不需要的時(shí)候終止。Looper.loop()方法是個(gè)死循環(huán),唯一跳出循環(huán)的方式是MessageQueue的next方法返回null。當(dāng)Looper的quit方法被調(diào)用時(shí),Looper就會(huì)調(diào)用MessageQueue的quit或者quitSafely方法來(lái)通知消息隊(duì)列退出,當(dāng)消息隊(duì)列被標(biāo)記為退出狀態(tài)時(shí),它的next方法就返回null。Loop必須退出,否則loop循環(huán)就會(huì)無(wú)限循環(huán)下去。loop方法會(huì)調(diào)用MessageQueue的next方法,而next方法是一個(gè)當(dāng)沒有消息時(shí) ,就是一個(gè)阻塞線程,便會(huì)導(dǎo)致Looper也會(huì)阻塞在那里。
Looper傳值到Handler
當(dāng)MessageQueue的next方法返回了新的消息,Looper就會(huì)處理這條消息:
(其實(shí)Looper就是通過(guò)這種方法把消息發(fā)給Handler)msg.target.disapatchMessage,這里msg.target是發(fā)送這條消息的Handler對(duì)象,消息交給dispatchMessage方法來(lái)處理。而這個(gè)dispatchMessage方法是在創(chuàng)建Handler時(shí)所用的Looper中執(zhí)行。這樣就把代碼邏輯切換到主線程。

當(dāng)手動(dòng)創(chuàng)建Looper時(shí):
主線程向子線程發(fā)送消息:首先handler肯定是要?jiǎng)?chuàng)建到子線程當(dāng)中,用于接收主線程發(fā)來(lái)消息進(jìn)行處理,但是,因?yàn)樽泳€程沒有l(wèi)ooper對(duì)象,首先需要調(diào)用looper.prepare(),當(dāng)主線程發(fā)來(lái)消息后,已經(jīng)準(zhǔn)備好的looper同樣會(huì)去消息隊(duì)列當(dāng)中循環(huán)消息,交給handler,但handler真正能夠使用該數(shù)據(jù)還得調(diào)用looper.loop()開啟循環(huán);

歡迎各位大佬批評(píng)

?著作權(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),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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