RecyclerView 源碼分析-開編

看了又看,任然對其一知半解。用了又用,發(fā)現(xiàn)其真的太美。RecyclerView的設(shè)計(jì)和書寫實(shí)在是太驚艷了,日常又使用的相當(dāng)頻繁。雖然之前就看過其他的源碼分析,故打算花點(diǎn)時(shí)間來親子動畫,對其來個了解,希望能向好的框架學(xué)習(xí),寫出這樣優(yōu)秀的代碼。

開始

既然是開始,當(dāng)然是先從RecyclerView本身開始。

有趣的類:

AdapterDataObserver 和RecyclerViewDataOberver類

1.首先,AdapterDataObserver是一個抽象類。

  • Observer base class for watching changes to an {@link Adapter}.

2.后者是前者的一個內(nèi)部實(shí)現(xiàn)類

來看他的具體方法。
里面還有判斷是不是每次都是增量式完成layout的。

ChildHelper類

  • Helper class to manage children.
    它是recyclerView的包裝類。提供兩套方法來通知子類。一種是忽略隱藏的view的。一種是不過濾的。

其中的bucket類在recycylerView中很常見,進(jìn)行位運(yùn)算的類?!

Bucket

其本身是一個鏈表的結(jié)構(gòu)。

如果一個對象有大量的是與非的狀態(tài)需要表示,通常我們會使用BitMask 技術(shù)來節(jié)省內(nèi)存,在 >Java 中,一個 byte 類型,有 8 位(bit),可以表達(dá) 8 個不同的狀態(tài),而 int 類型,則有 32 >位,可以表達(dá) 32 種狀態(tài)。再比如Long類型,有64位,則可以表達(dá)64中狀態(tài)。一般情況下使用一個>Long已經(jīng)足夠我們使用了。但如果有不設(shè)上限的狀態(tài)需要我們表示呢?在ChildHelper里有一個靜>>態(tài)內(nèi)部類Bucket

可以看到,Bucket是一個鏈表結(jié)構(gòu),當(dāng)index大于64的時(shí)候,它便會去下一個Bucket去尋找,所以,Bucket可以不設(shè)上限的表示狀態(tài)。

CallBack

內(nèi)部類CallBack其實(shí)就是RecyclerView來實(shí)現(xiàn)其方法

Recycler類

也是一個內(nèi)部類,是管理回收(scrapped)或者分離(detached)的內(nèi)部管理類。
有l(wèi)ayoutmanager來控制recycler中獲得對應(yīng)的view

scrapped view

dirty or clean

dirty view需要重繪,而clean view不需要重繪和布局,直接由layoutmanager而使用

其中保存這 attached viewholder 和 changed viewholder

mUnmodifiableAttachedScrap 發(fā)現(xiàn)有一個集合。是有attached viewholder復(fù)制而來的不可重繪的副本。(通過java Collections.unmodifiableList()
[參考鏈接-Collections方法說明][1]

閱讀參考鏈接,得知,這是一種通用的重構(gòu)中使用的手法。

在《重構(gòu)——改善既有代碼的設(shè)計(jì)》一書中,有一種重構(gòu)手法叫Encapsulate Collection >,(封裝集合)
使用這種方法重構(gòu)的意義:就好比我們網(wǎng)上購物一樣,你可以往購物車添加自己想買的東西,但是>商戶不能在不通知顧客(我們)的情況下,就任意的添加商品,并修改商品的價(jià)格等,入口只能是>一個,也就是在顧客手中。比喻可能不是很恰當(dāng),反正意思大概就是這樣。

這個方法還是挺有意思的。將自己所包含的集合封裝起來提供給其他的使用者。避免使用的時(shí)候發(fā)生改變。

其中有一個RecyclerViewPool的內(nèi)部類

RecycledViewPool lets you share Views between multiple RecyclerViews.
可以在不同的recyclerView中使用相同的pool。也可以讓其自己創(chuàng)建。

  • ScrapData類。 這個類的英語注釋沒有看懂。當(dāng)時(shí)其實(shí)應(yīng)該是保存viewholder的緩存的地方。無論是在構(gòu)建還是在綁定數(shù)據(jù)時(shí)。而且還提供了平均綁定數(shù)據(jù)和創(chuàng)建viewholder的計(jì)時(shí)。后面一個功能沒有看懂。

  • 根據(jù)viewType 來保存scrapData 再有srcapData來保存viewHolder.這里看到默認(rèn)的堆大小為5,就是說相同種類的viewholder默認(rèn)的保存數(shù)量是5個?

  • runningAverage方法? 來的時(shí)間的權(quán)重在3/4 新時(shí)間占1/4

  • factorIn...方法和 willxxxInTime方法提供的是一種時(shí)間的判斷??

  • attachCount的計(jì)數(shù)

[對緩存機(jī)制的理解][2]

這里文章里面對緩存機(jī)制的描述相當(dāng)?shù)耐笍亍?/p>

  • 首先是,View的detach和remove的區(qū)別:
  1. detach: 在ViewGroup中的實(shí)現(xiàn)很簡單,只是將ChildView從ParentView的ChildView數(shù)組中移除,ChildView的mParent設(shè)置為null, 可以理解為輕量級的臨時(shí)remove, 因?yàn)閂iew此時(shí)和View樹還是藕斷絲連, 這個函數(shù)被經(jīng)常用來改變ChildView在ChildView數(shù)組中的次序。View被detach一般是臨時(shí)的,在后面會被重新attach。
  2. remove: 真正的移除,不光被從ChildView數(shù)組中除名,其他和View樹各項(xiàng)聯(lián)系也會被徹底斬?cái)?不考慮Animation/LayoutTransition這種特殊情況), 比如焦點(diǎn)被清除,從TouchTarget中被移除等。
  • RecyclerView的Scrap View:
    Scrap View指的是在RecyclerView中,處于根據(jù)數(shù)據(jù)刷新界面等行為, ChildView被detach(注意這個detach指的是1中介紹的detach行為,而不是RecyclerView一部分注釋中的”detach”,RecyclerView一部分注釋中的”detach”其實(shí)指得是上面的remove),并且被存儲到了Recycler中,這部分ChildView就是Scrap View。
    ViewHolder有一個Flag: FLAG_TMP_DETACHED代表的就是1中介紹的detach, 這也印證了2的推測,RecyclerView將remove視為”detach”, detach視為”tmp_detach”

  • 其中還有對于RecyclerViewPool的描述

  1. RecycledViewPool作為第三級ViewHolder緩存,立足于RecyclerView之間的ViewHolder共享。
    RecycledViewPool是有容量限制的。

這里所的三級緩存還未理解到完整的結(jié)構(gòu)。等到后面來完整的梳理。
以ViewType作為key來分類存放ViewHolder,每類ViewType都有單獨(dú)容量限制,可以通過setMaxRecycledViews來為每種ViewType指定不同的容量限制。

  1. 被加入到RecycledViewPool的ViewHolder會被reset,只保留itemView使得View可以被復(fù)用, 基本是一個半裸的ViewHolder。

ps:這里也是之前沒理解的每一個viewholder加入時(shí),會被執(zhí)行 resetInternal方法。

  1. RecycledViewPool在沒有被顯式指定的情況下,如果被調(diào)用,RecyclerView會自動創(chuàng)建一個。
  2. RecycledViewPool還有一套attach/detach機(jī)制來在Adapter 變化時(shí)選擇性的釋放舊緩存。

ViewCacheExtension

既然有了viewholder緩存的pool類,為什么又有一個viewCacheExtension類呢?它是做什么的呢?

  • 文檔中所說是提供了一種額外緩存層級的來幫助開發(fā)者管理視圖的類。
    調(diào)用java getViewForPosition時(shí)。如果沒有合適的view Recycler會提供緩存的view來作為第一級的緩存。如果找不到合適的veiw,它會滴啊用 getViewForPositionAndType 在檢查RecycledViewPool之前。

也就是說。ViewCacheExtension 是介于一級緩存和RecyclerViewPool的緩存之間。
其只提供了一個方法。getViewForPosition來提供緩存的類。

這樣的三級緩存就呼之欲出。但是三級緩存有什么好處呢?通常不是一級緩存就能解決問題了嗎?

暫時(shí)到這里吧。明天繼續(xù)分析recycler中的代碼

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

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

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