溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

android中MessageQueue.IdleHandler的作用是什么

發(fā)布時(shí)間:2021-06-28 17:34:25 來(lái)源:億速云 閱讀:141 作者:Leah 欄目:移動(dòng)開(kāi)發(fā)

android中MessageQueue.IdleHandler的作用是什么,針對(duì)這個(gè)問(wèn)題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問(wèn)題的小伙伴找到更簡(jiǎn)單易行的方法。

通過(guò)Handler向Looper包含的MessageQueue投遞Message

android中MessageQueue.IdleHandler的作用是什么

一般我們比較少接觸MessageQueue, 其實(shí)它內(nèi)部的IdleHandler接口有很多有趣的用法,首先看看它的定義:

android中MessageQueue.IdleHandler的作用是什么

簡(jiǎn)而言之,就是在looper里面的message暫時(shí)處理完了,這個(gè)時(shí)候會(huì)回調(diào)這個(gè)接口,返回false,那么就會(huì)移除它,返回true就會(huì)在下次message處理完了的時(shí)候繼續(xù)回調(diào),讓我們看看它有哪些有趣的用法吧~~

一、提供一個(gè)android沒(méi)有的聲明周期回調(diào)時(shí)機(jī)

如果有這種需求,想要在某個(gè)activity繪制完成去做一些事情,那這個(gè)時(shí)機(jī)是什么時(shí)候呢?有同學(xué)可能覺(jué)得onResume()是一個(gè)合適的機(jī)會(huì),不是可是這個(gè)onResume() 真的是各種繪制都已經(jīng)完成才回調(diào)的嗎?No, too naive ~~

android中MessageQueue.IdleHandler的作用是什么

你看谷老師說(shuō)了,onStart是用戶可見(jiàn),onResume是用戶可交互,谷老師可沒(méi)說(shuō)onResume是繪制完成吧~那么android那些耗時(shí)的measure, layout, draw是在什么時(shí)候執(zhí)行的呢?它們跟onResume()又有何關(guān)系呢?讓我們先來(lái)看看源碼吧~

1. ActivityThread.java

我們知道app的進(jìn)程其實(shí)是ActivityThread, 那么activity的生命周期自然是它來(lái)執(zhí)行了,

android中MessageQueue.IdleHandler的作用是什么

performResumeActivity就是回調(diào)onResume了, 我們繼續(xù)看wm.addView方法, 這個(gè)ViewManager是一個(gè)接口,其實(shí)現(xiàn)者是WindowManagerImpl

2.WindowManagerImpl.java

android中MessageQueue.IdleHandler的作用是什么

這個(gè)mGlobal是WindowManagerGlobal對(duì)象,我們繼續(xù)

3.WindowManagerGlobal.java

android中MessageQueue.IdleHandler的作用是什么

這里我們new 出了ViewRootImpl對(duì)象, 我們知道這個(gè)對(duì)象就是android view的根對(duì)象了,負(fù)責(zé)view繪制的measure, layout, draw的巨長(zhǎng)的方法 performTraversals就是這個(gè)類的,我們繼續(xù)看setView方法

4.ViewRootImpl.java

android中MessageQueue.IdleHandler的作用是什么

這個(gè)函數(shù)調(diào)用了關(guān)鍵方法requestLayout(), 我們繼續(xù)跟蹤,順便說(shuō)下,后面一連串的BadTokenException就是我們常常遇到的dialog相關(guān)拋出的,也有些特殊場(chǎng)景也會(huì)出這個(gè)異常,可以到這里查看線索。

android中MessageQueue.IdleHandler的作用是什么

調(diào)用了scheduleTraversals, 從名字就能看出來(lái)了吧:

android中MessageQueue.IdleHandler的作用是什么

它往Choreographer里面post了一個(gè)runnable, 這個(gè)Choreographer是android負(fù)責(zé)幀率刷新相關(guān)的東西,我們暫時(shí)可以不關(guān)注它,可以理解為往主線程post一個(gè)消息是一樣的,順便說(shuō)下這個(gè)Choreographer可以做幀率檢測(cè)相關(guān)的東西,,可以用于卡頓檢測(cè)什么的···

android中MessageQueue.IdleHandler的作用是什么
android中MessageQueue.IdleHandler的作用是什么

我們看這個(gè)runnable果然是去執(zhí)行了那個(gè)巨長(zhǎng)無(wú)比的函數(shù)performTraversals函數(shù), 現(xiàn)在我們可以總結(jié)下流程了:

android中MessageQueue.IdleHandler的作用是什么

結(jié)論:所以如果我們想在界面繪制出來(lái)后做點(diǎn)什么,那么在onResume里面顯然是不合適的,它先于measure等流程了, 有人可能會(huì)說(shuō)在onResume里面post一個(gè)runnable可以嗎?還是不行,因?yàn)槟菢泳蜁?huì)變成這個(gè)樣子

android中MessageQueue.IdleHandler的作用是什么

所以你的行為一樣會(huì)在繪制之前執(zhí)行,這個(gè)時(shí)候我們的主角IdleHandler就發(fā)揮作用了,我們前面說(shuō)了,它是在looper里面message暫時(shí)執(zhí)行完畢了就會(huì)回調(diào),顧名思義嘛,Idle就是隊(duì)列為空的意思,那么我們的onResume和measure, layout, draw都是一個(gè)個(gè)message的話,這個(gè)IdleHandler就提供了一個(gè)它們都執(zhí)行完畢的回調(diào)了,大概就是這樣

android中MessageQueue.IdleHandler的作用是什么

說(shuō)了這么多,那么現(xiàn)在獲取到這個(gè)時(shí)機(jī)有什么用呢? look?。?/p>

這個(gè)是我們地圖的公交詳情頁(yè)面, 進(jìn)入之后產(chǎn)品要求左邊的頁(yè)卡需要展示,可以看到左邊的頁(yè)卡是一個(gè)非常復(fù)雜的布局,那么進(jìn)入之后的效果可以明顯看到頭部的展示信息是先顯示空白再100毫秒左右之后才展示出來(lái)的,原因就是這個(gè)頁(yè)卡的內(nèi)容比較復(fù)雜,用數(shù)據(jù)向它填充的時(shí)候花了較長(zhǎng)時(shí)間,代碼如下:

android中MessageQueue.IdleHandler的作用是什么

android中MessageQueue.IdleHandler的作用是什么

可以看到這個(gè)detailView就是這個(gè)側(cè)滑的頁(yè)卡了,填充里面的數(shù)據(jù)花了90ms,如果這個(gè)時(shí)間是用在了界面view繪制之前的話,就會(huì)出現(xiàn)以上的效果了,view先是白的,再出現(xiàn),這樣就體驗(yàn)不好了,如果我們把它放到IdleHandler里面呢?代碼如下:

android中MessageQueue.IdleHandler的作用是什么

效果是這樣的:

看出不同了嗎?頂部的頁(yè)卡先展示出來(lái)了,這樣體驗(yàn)是不是會(huì)更好一些呢。雖然只有短短90ms,不過(guò)我們做app也應(yīng)該關(guān)注這種細(xì)節(jié)優(yōu)化的,是吧~ 這個(gè)做法也提供了一種思路,android本身提供的activity框架和fragment框架并沒(méi)有提供繪制完成的回調(diào),如果我們自己實(shí)現(xiàn)一個(gè)框架,就可以使用這個(gè)IdleHandler來(lái)實(shí)現(xiàn)一個(gè)onRenderFinished這種回調(diào)了。

二、可以結(jié)合HandlerThread, 用于單線程消息通知器

我們先思考一個(gè)問(wèn)題,如果有一個(gè)model數(shù)據(jù)管理模塊,怎么設(shè)計(jì)?比如地圖的收藏模塊的model部分。就是下面這個(gè)圖的小星星:

它原來(lái)的model設(shè)計(jì)大概是這個(gè)樣子的:

android中MessageQueue.IdleHandler的作用是什么

由于這個(gè)model是單例的,而且是多線程可以訪問(wèn)的,所以它的增刪改查都加上了鎖,而且由于外部訪問(wèn)需要遍歷有哪些收藏點(diǎn),所以外部遍歷列表也需要加鎖,大概是這樣的:

android中MessageQueue.IdleHandler的作用是什么

因?yàn)槭嵌嗑€程可訪問(wèn)的,如果遍歷不加鎖的話,其他線程刪除了一個(gè)收藏,就會(huì)crash的,原來(lái)的這樣設(shè)計(jì)有幾個(gè)不好的地方:

1. 外部使用者需要關(guān)系鎖的使用,增加了負(fù)擔(dān),不用還不安全

2. 如果在主線程加鎖的話,可能另一個(gè)線程執(zhí)行操作會(huì)阻塞主線程造成anr

總之,多線程代碼就是容易出錯(cuò),而且真的出錯(cuò)的時(shí)候查起來(lái)太費(fèi)勁了,目前收藏夾模塊就有N多bug,所以我想用單線程來(lái)解決這個(gè)問(wèn)題,由于model層的訪問(wèn)需要數(shù)據(jù)庫(kù)和網(wǎng)絡(luò)等,所以需要異步線程,那么單線程隊(duì)列+異步線程,首先想到的就是HandlerThread, 大概架構(gòu)如下:

android中MessageQueue.IdleHandler的作用是什么

現(xiàn)在,我們把原來(lái)多線程的邏輯改到了單線程里面,各種收藏的model共用一個(gè)HandlerThread,這樣我們?cè)鰟h改查都不用加鎖了,出錯(cuò)幾率大大減小,而且這種model的設(shè)計(jì)有點(diǎn)類似插件的意思,可以很方便的增加其他收藏。

Ok, 那么跟我們的主題IdleHandler有什么關(guān)系呢?思考這樣一個(gè)問(wèn)題,地圖上的小星星需要實(shí)時(shí)更新,也就是model的任何變化都需要顯示到地圖上,那么收藏的小星星就應(yīng)該作為model的觀察者,以前的做法是向收藏model注冊(cè)監(jiān)聽(tīng),在每一個(gè)增刪改查操作后都對(duì)觀察者回調(diào),大概是這樣:

android中MessageQueue.IdleHandler的作用是什么

這樣有一個(gè)小小的問(wèn)題,就是如果有一個(gè)操作生成10個(gè)快速連續(xù)的增刪改查操作,那么我們的UI就會(huì)收到10次回調(diào),而這種場(chǎng)景下我們其實(shí)只需要最后一次回調(diào)就夠了,中間操作其實(shí)不用刷新UI的。

那么現(xiàn)在改成單線程模型,我們又該如何處理這個(gè)問(wèn)題呢?當(dāng)然我們也能在每個(gè)post到異步線程的runnable里面去回調(diào)觀察者,但這樣未免不夠優(yōu)雅,所以這個(gè)時(shí)候IdleHandler不就又可以發(fā)揮作用了嗎?它是在消息暫時(shí)處理完的時(shí)候回調(diào)的呀,不是很符合我們的時(shí)機(jī)么,對(duì)吧?

android中MessageQueue.IdleHandler的作用是什么

就是這個(gè)樣子了,這里為什么不用第一個(gè)場(chǎng)景下的Looper.myQueue().addIdleHandler()呢?注意這個(gè)地方Looper.myQueue()如果在主線程調(diào)用就會(huì)使用主線程looper了,所以我選擇反射這個(gè)HandlerThread的looper來(lái)設(shè)置它,這個(gè)IdleHandler我們返回了true, 表示我們要長(zhǎng)期監(jiān)聽(tīng)消息隊(duì)列,因?yàn)榉祷豧alse,下次就沒(méi)有回調(diào)了哦。

關(guān)于android中MessageQueue.IdleHandler的作用是什么問(wèn)題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒(méi)有解開(kāi),可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識(shí)。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI