簡介
RecyclerView簡稱RV逆日,是ListView和GridView的加強(qiáng)版。
常規(guī)使用步驟
-
設(shè)置布局管理器(必須的)
RecyclerView.setLayoutManager()
-
設(shè)置適配器(必須的)
RecyclerView.setAdapter()
-
設(shè)置Item的裝飾器(非必須的)
RecyclerView.setItemAnimator()
-
設(shè)置Item的動畫(非必須的)
RecyclerView.addItemDecoration()
RecyclerView的繪制流程分析
按照 onMeasure() ---> onLayout() ---> onDraw()流程去分析
onMeasure()
- RecyclerView的測量過程是委托給LayoutManager來完成
- LayoutManager中的測量工作
- 如果RecyclerView的寬和高都設(shè)置了match_parent或者具體數(shù)值辣之,那么就調(diào)用LayoutManager中的onMeasure()方法來進(jìn)行測量
- 如果RecyclerView設(shè)置的是wrap_content,就會執(zhí)行RecyclerView中的dispatchLayoutStep2()方法來進(jìn)行測量
- 其中RecyclerView中的dispatchLayoutStep1()方法是和RecyclerView中的Item動畫相關(guān)府蔗。
onLayout()
- RecyclerView的布局過程是委托給LayoutManager來完成后的
- onLayout方法中,核心方法是 dispatchLayout()
- 在onMeasure方法中沒有調(diào)用dispatchLayoutStep2()去測量子View檩帐,會在此方法中調(diào)用去測量崖面。
- disPatchLayoutStep2()方法的核心就是調(diào)用LayoutManager的onLayoutChildren()方法去測量子View的大小元咙,并確定子View的位置
- 其中LayoutManager中的onLayoutChildren()方法是一個空方法,我們熟悉的LienarLayout巫员、GridLayoutManager庶香、StaggeredlayoutManager都對該方法進(jìn)行了重寫,有自己的實(shí)現(xiàn)方式简识。
- 看下LinearLayout的onLayoutChildren()方法
- 核心是fill()方法
- 在fill()方法赶掖,通過while循環(huán)來判斷時候有過剩的空間來足夠繪制一個完整的子View
- 其中l(wèi)ayoutChunk方法是子View測量布局的真正實(shí)現(xiàn)。
- layoutChunk方法是一個非常核心的方法七扰。該方法執(zhí)行一次就將子View填充到RV中奢赂。
- 其中會調(diào)用 layoutState.next()方法,獲取到一個View(實(shí)際是從緩存中查找ViewHolder或者創(chuàng)刊一個新的ViewHolder颈走,拿到ViewHolder綁定的View)
onDraw()
測量和布局的過程完畢膳灶,接下來就是繪制的操作
- 很簡單,如果有添加ItemDecoration立由,那么就遍歷取出轧钓,然后進(jìn)行繪制操作
RecyclerView中的緩存復(fù)用原理Recycler
RV中的緩存復(fù)用主要體現(xiàn)在ViewHolder的緩存和復(fù)用
- RV對ViewHolder的緩存和復(fù)用的核心代碼都是在RV的內(nèi)部類Recycler中完成的司致。
Recycelr的分級緩存
- 一級緩存(mAttachedScrap和mChangeScrap)
- 一級緩存主要是用來緩存屏幕中的ViewHolder
- 場景
- 第一次我們調(diào)用setLayoutManger和setAdapter之后,Rv會進(jìn)行一次layout并顯示到屏幕中聋迎,此時的ViewHolder是經(jīng)過onCreateViewHolder創(chuàng)建的。
- 我們進(jìn)行下拉刷新請求到數(shù)據(jù)的時候枣耀,會調(diào)用notifyXX的方法霉晕,此時會將屏幕中的可見的ViewHolder緩存到Scarp中,當(dāng)緩存完之后捞奕,然后從Recycler的從緩存中根據(jù)postion獲取相應(yīng)的ViewHolder牺堰,之后將數(shù)據(jù)更新到相應(yīng)的ViewHolder中。最后再將這些ViewHolder繪制到屏幕上颅围。
- 二級緩存(mCachedViews)
- 主要用來緩存屏幕之外的ViewHolder伟葫,緩存的容量為2個。(這個容量是可以通過setViewCacheSize方法來改變的)
- 當(dāng)緩存的容量已經(jīng)滿了院促,當(dāng)有新的ViewHolder要進(jìn)行緩存的話筏养,就根據(jù)FIFO規(guī)則將舊的ViewHolder從緩存中移除。
- 注意:剛被移除屏幕之外的ViewHolder通常會立即被使用到常拓,所以被移除屏幕之外的ViewHolder不會被立即標(biāo)記為無效ViewHolder渐溶,而是將它緩存在cache中 (也就是mCachedViews中),但是又不能將所有移除屏幕之外的ViewHolder都視為非無效的弄抬。所以它的緩存大小為2茎辐。
- 如果在二級緩存中沒有找到符合條件的ViewHolder,即使二級緩存中存在ViewHolder掂恕,LayoutManager也不會從二級緩存中取ViewHolder拖陆,而是到四級緩存中取出一個ViewHolder,然后在onBindViewHolder中給ViewHolder重新設(shè)置數(shù)據(jù)懊亡。
- 三級緩存(ViewCacheExtension)
- 這是RV預(yù)留給我們開發(fā)人員的一個抽象類依啰,我們可以繼承這個抽象類,復(fù)寫抽象方法斋配,來自定義自己的緩存機(jī)制孔飒。
- 四級緩存(RecycledViewPool)
- 也是用來緩存屏幕之外的ViewHodler,主要是用來緩存從二級緩存中淘汰的ViewHolder
- 當(dāng)ViewHolder緩存到RecycledViewPool中的時候艰争,會將數(shù)據(jù)從ViewHodler中清空坏瞄,當(dāng)再次使用時候會調(diào)用onBindView重新設(shè)置數(shù)據(jù)
- 多個RV可以共享一個RecycledViewPool。
- 也是用來緩存屏幕之外的ViewHodler,主要是用來緩存從二級緩存中淘汰的ViewHolder
RV從緩存中取出ViewHolder
- 在 onlayout過程中甩卓,layoutChunk方法通過layoutState.next方法拿到某一個子View鸠匀,然后添加到RV中
- 在layoutState.next()方法中,通過getViewForPosition()方法獲取到View
- getViewForPosition()方法調(diào)用了tryGetViewHolderforPositionByDealine()方法
- 在tryGetViewHolderforPositionByDealine()方法中會依次調(diào)用這4幾緩存查找相應(yīng)位置的ViewHolder
- 在緩存中都沒有找到逾柿,就調(diào)用onCreateViewHolder()方法創(chuàng)建一個新的ViewHolder