Handler執(zhí)行流程
首先handler作為任務執(zhí)行者,一般創(chuàng)建在主線程哭廉,當子線程有需要發(fā)送的數(shù)據(jù)脊僚,通過創(chuàng)建message對象,使用handler對象將消息發(fā)送到messagequeue遵绰,messagequeue遵循了隊列先進先出的原則辽幌,當主線程的looper循環(huán)消息的時候,會按照messagequeue隊列的順序循環(huán)消息椿访,并將消息給到任務執(zhí)行者handler去執(zhí)行任務乌企。
Handler的作用以及工作原理
作用:因為在Android中,主線程不建議做耗時的操作成玫,子線程不建議更新UI加酵,但是Android開發(fā),其實就是搭建好頁面哭当,將服務器的數(shù)據(jù)展示到頁面上猪腕,所以使用網(wǎng)絡請求會非常頻繁,而網(wǎng)絡請求屬于耗時操作钦勘,需要放到子線程完成陋葡,但一般情況下也不會通過子線程更新UI,需要將請求成功的數(shù)據(jù)發(fā)送到主線程進行UI更新彻采,所以一般會使用到handler腐缤。
下面再來說說工作原理
工作原理:Handler創(chuàng)建完成后,內(nèi)部的Looper以及MessageQueue就可以和Handler一起協(xié)同工作肛响,然后通過Hadler的post方法將一個Runnable投遞到Handler內(nèi)部的Looper中去處理岭粤,也可以通過Handler的send方法發(fā)送一個消息,這個消息會在Looper中做處理特笋。Post最終也是通過send來完成的剃浇。當Handler的send方法被調(diào)用時,他會調(diào)用MessageQueue的enqueueMessage方法將這個消息放入消息隊列中雹有,然后Looper發(fā)現(xiàn)有新消息到來時偿渡,就會處理這個消息,最終消息中的Runnable或者Handler的handlerMessage方法就會被調(diào)用霸奕。Looper是運行在Handler所在的線程溜宽,所以就把業(yè)務邏輯切換到主線程了。
ThreadLocal的工作原理
ThreadLocal的定義:ThreadLocal是線程內(nèi)部的數(shù)據(jù)存儲類质帅,通過他可以在指定的線程中存儲數(shù)據(jù)适揉,該數(shù)據(jù)只有在指定線程中可以獲取留攒。
ThreadLocal使用場景:當某些數(shù)據(jù)是以線程為作用域,并且不同線程具有不同的數(shù)據(jù)副本的時候嫉嘀;另外還可以使用在復雜邏輯下的對象傳遞炼邀。比如監(jiān)聽器的傳遞 ,
ThreadLoal的值在table數(shù)組中的存儲位置總是為ThreadLocal的reference字段所標識的對象的下一個位置剪侮。ThreasdLoacal的set和get方法所操作的對象都是當前線程的localValues對象的table數(shù)組拭宁,因此在不同的線程中訪問同一個ThreadLocal的set和get方法,他們對ThreadLocal所做的讀寫操作僅限于各自線程的內(nèi)部瓣俯,從而實現(xiàn)在多個線程中互不干擾的存儲和修改數(shù)據(jù)杰标。
Looper的工作原理
Looper在Android的消息機制中扮演著消息循環(huán)的角色,就是不停的從MessageQueue中查看是否有新消息彩匕,如果有消息就立刻處理腔剂,否則就一直阻塞在那里,首先在構(gòu)造方法中創(chuàng)建一個MessageQueue即隊列消息驼仪,然后將當前的對象保存起來掸犬。Looper除了prepare方法外,還提供了prepareMainLooper方法(這就是我們在MainActivity里并沒有聲明Lopper)绪爸,這個方法主要是給主線程也就是ActivityThread創(chuàng)建Looper使用的湾碎,其本質(zhì)也是通過prepare方法來實現(xiàn)的。由于主線程的Looper比較特殊毡泻,所以Looper提供了一個getMainLooper方法胜茧,通過它可以在任何地方獲取到主線程的Looper。
Looper的相關(guān)方法
Looper也是可以退出的仇味,Looper提供了quit和quitSafely來退出一個Looper,二者的區(qū)別是:quit會直接退出Looper雹顺,而quieSafely只是假定一個特殊標記丹墨,然后把消息隊列中的已有消息處理完畢后才安全退出。Looper退出后嬉愧,通過Handler發(fā)送消息失敗贩挣,這個時候Handler的send方法會返回false。在子線程中没酣,如果手動為其創(chuàng)建Looper王财,那么在所有的事情完成以后應該調(diào)用quit方法來終止消息循環(huán),否則這個子線程就會一直處于等待狀態(tài)裕便,而如果想退出Looper以后绒净,這個線程就會立刻終止,因此建議不需要的時候終止偿衰。Looper.loop()方法是個死循環(huán)挂疆,唯一跳出循環(huán)的方式是MessageQueue的next方法返回null改览。當Looper的quit方法被調(diào)用時,Looper就會調(diào)用MessageQueue的quit或者quitSafely方法來通知消息隊列退出缤言,當消息隊列被標記為退出狀態(tài)時宝当,它的next方法就返回null。Loop必須退出胆萧,否則loop循環(huán)就會無限循環(huán)下去庆揩。loop方法會調(diào)用MessageQueue的next方法,而next方法是一個當沒有消息時 跌穗,就是一個阻塞線程订晌,便會導致Looper也會阻塞在那里。
Looper傳值到Handler
當MessageQueue的next方法返回了新的消息瞻离,Looper就會處理這條消息:
(其實Looper就是通過這種方法把消息發(fā)給Handler)msg.target.disapatchMessage腾仅,這里msg.target是發(fā)送這條消息的Handler對象,消息交給dispatchMessage方法來處理套利。而這個dispatchMessage方法是在創(chuàng)建Handler時所用的Looper中執(zhí)行推励。這樣就把代碼邏輯切換到主線程。
當手動創(chuàng)建Looper時:
主線程向子線程發(fā)送消息:首先handler肯定是要創(chuàng)建到子線程當中肉迫,用于接收主線程發(fā)來消息進行處理验辞,但是,因為子線程沒有l(wèi)ooper對象喊衫,首先需要調(diào)用looper.prepare(),當主線程發(fā)來消息后跌造,已經(jīng)準備好的looper同樣會去消息隊列當中循環(huán)消息,交給handler族购,但handler真正能夠使用該數(shù)據(jù)還得調(diào)用looper.loop()開啟循環(huán);
歡迎各位大佬批評