在Android中株憾,Handler是我們最常用的消息處理類凑保,也是系統(tǒng)中非常重要的類挟裂,所以它的原理我們也應(yīng)該十分的清楚了解享钞,所以Handler,Looper诀蓉,MessageQueue成了我們必須學(xué)習(xí)和理解的東西栗竖,但是其中有一個(gè)接口很少被提及和使用,那就是IdleHandler渠啤。
一狐肢、源碼解析
根據(jù)注釋我們很清楚的知道,這個(gè)接口方法是在消息隊(duì)列消息隊(duì)列全部處理完成后或者是在阻塞的過程中等待更多的消息的時(shí)候調(diào)用的沥曹,返回值絕對了處理一次后是否保存這個(gè)接口份名。雖然注釋很清楚,但是我們更多的應(yīng)該是要知道他是怎么處理的妓美,所以看源碼:
先看下接口的添加和刪除:
從上面所貼出的源碼中我們可以得到兩點(diǎn):
1僵腺、添加和刪除是線程安全的
2、通過查找可以得知mIdleHandlers是一個(gè)ArrayList壶栋,因此這個(gè)接口是可以重復(fù)添加的辰如,不必?fù)?dān)心被替換問題
接下來我們看看接口是如何被調(diào)用的,通過源碼查找贵试,我們知道了它是在next()方法中調(diào)用的琉兜,同時(shí)我們也知道,這個(gè)方法也是消息隊(duì)列用來循環(huán)消息的地方毙玻,由于方法比較長豌蟋,我就只貼部分關(guān)鍵源碼:
其實(shí)這部分源碼注釋都已經(jīng)很清楚了
第一部分應(yīng)該算是條件判斷,首先判斷的是是不是第一次桑滩,pendingIdleHandlerCount的初始化為-1梧疲,其次判斷的是有沒有IdleHandler接口,如果沒有的話就是阻塞
第二部分是接口處理运准,主要是接口的調(diào)用以及判斷是不是接口只運(yùn)行一次就不需要了幌氮,最后是設(shè)置判斷的條件
二、系統(tǒng)源碼中的IdleHandler使用
通過上面的源碼分析可以找到戳吝,他是空閑時(shí)調(diào)用浩销,這一定是一個(gè)非常有用的接口。于是在系統(tǒng)源碼中查找它的使用听哭,發(fā)現(xiàn)了一點(diǎn)小小的驚喜慢洋,在這里分享給大家
在對源碼的學(xué)習(xí)中塘雳,我發(fā)現(xiàn)了IdleHandler的蹤跡,他出現(xiàn)的位置也是很關(guān)鍵的位置普筹,在ActivityThread中败明,學(xué)習(xí)過源碼的同學(xué)都知道,這是一個(gè)非常重要的類太防,因?yàn)槠鋵?shí)這才算是一個(gè)程序的入口妻顶,額,有點(diǎn)遠(yuǎn)了蜒车,有興趣的同學(xué)可以自己去看下這個(gè)類讳嘱,不多說,上源碼
上面的代碼很簡單酿愧,主要是添加和移除接口沥潭,以及接口實(shí)現(xiàn),但是接口實(shí)現(xiàn)的時(shí)候有個(gè)小驚喜啊嬉挡,看方法名稱就很意外doGcIfNeeded()钝鸽,這個(gè)地方涉及到回收。大家都知道系統(tǒng)會自動回收庞钢,但是什么時(shí)候回收拔恰,哪個(gè)地方回收的,一直都很模糊基括,現(xiàn)在總算知道一點(diǎn)了颜懊,但是這僅僅是一個(gè)方面的回收,不要當(dāng)成全部
這個(gè)也很簡單了阱穗,主要是2次回收有最小時(shí)間間隔饭冬,就不多說了
Tips:
如果沒看過ActivityThread可能不知道上面的Looper.myQueue()指的是哪個(gè)Looper這里給大家說明下使鹅,還是先上源碼:
使用過Looper的人應(yīng)該都很明白這個(gè)揪阶,從代碼中可以看出,這個(gè)地方準(zhǔn)備的是主線程患朱,所以回收添加的Looper是MainLooper鲁僚,另外大家不會忘了main方法吧:-D
三、其他源碼中的使用
請大家原諒我年輕裁厅,閱讀的開源代碼比較少冰沙,也可能是其他的開源項(xiàng)目中沒有這樣的需求,所以只在Glide中看到過這個(gè)接口的使用执虹,Google不愧為最了解源碼的啊拓挥,源碼貼給大家
Glide是一個(gè)面向接口的開源項(xiàng)目,而且寫的很高明袋励,本人的JAVA功底比較薄弱侥啤,所以看起來有點(diǎn)吃力当叭,就不給大家具體解釋了,大家有興趣可以自己去查看盖灸,同時(shí)也希望有大神分析下Glide的源碼蚁鳖,膜拜。