RecycleView深入學習

RecyclerView真的是寶藏View,學習記錄。 

一個不太常用的屬性,作用不太容易描述,可以自己測試一下。

android:clipToPadding="false"
android:paddingBottom="@dimen/x10"
val linearLayoutManager = LinearLayoutManager(this)
linearLayoutManager.orientation = LinearLayoutManager.VERTICAL
val mDivider = LinearItemDecotation(this)
val adapter = RecyclerAdapter(this, mDatas)

mRecycler.layoutManager = linearLayoutManager
mRecycler.addItemDecoration(mDivider)
mRecycler.adapter = adapter

Adapter中的主要方法:

class RecyclerAdapter(context: Context, mDatas: ArrayList<String>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    override fun onCreateViewHolder(p0: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
    }

    override fun onBindViewHolder(p0: RecyclerView.ViewHolder, p1: Int) {
    }
}

onCreateViewHolder會在創建一個新View的時候調用
onBindViewHolder會在已經存在的View綁定數據時調用。
如果新創建的View,則會先調用onCreateViewHolder來創建View,然後調用onBindViewHolder來綁定數據,如果是複用的View,就會只調用onBindViewHolder。

RecyclerView回收原理

RecyclerView中用兩級緩存(mCachedViews和mRecyclerPool)來保存這些已經被廢棄(Removed)的HolderView。這兩個緩存區別是:mCacheViews是第一級緩存,他的size是2,只能保存兩個HolderView,始終保存最新被移除的HolderView。當mCachedViews滿了以後,會利用先進先出原則,把老的HolderView存放到mRecyclerPool中,在mRecyclerPool中,他默認size是5。

detachAndScrapAttachedViews(recycler);的作用是將屏幕上所有的HolderView與屏幕分離,將他們從RecyclerView佈局中拿下來,然後存放在一個列表中,在重新佈局時,把這些HolderView重新一個個放在新位置上。將屏幕中的HolderView從RecyclerView中拿下來存放在mAttachedScrap列表中。mAttachedScrap中存儲的就是重新佈局前從RecyclerView中剝離出來的當前顯示在屏幕中的HolderView。這些HolderView不參與回收複用,單純只是爲了先從RecyclerView中拿下來,然後再重新佈局。新佈局中沒有用到的HolderView,會從mAttachedScrap中移到mCachedViews中,重新參與複用。

RecyclerView允許我們自己擴展回收池,並且給他預留了一個變量mViewCacheExtension,一般不會用到。

至此,在RecyclerView中,總共有四個池子:mAttachedScrap、mCachedViews、mViewCacheExtension、mRecyclerPool。

  1. mAttachedScrap不參與回收複用,只保存重新佈局時,從RecyclerView中取出的顯示在當前屏幕上的hoderView列表。
  2. mCachedViews、mViewCacheExtension、mRecyclerPool總成了回收複用的三級緩存。當RecyclerView要拿一個複用的HolderView時,獲取優先級是:mCachedViews>mViewCacheExtension>mREcyclerPool。一般我們不會自定義mViewCacheExtension,所以獲取緩存的順序其實爲mCachedViews>mRecyclerPool。
  3. 其實mCachedViews是不參與回收複用的,他的作用就是保存最新被移除的HolderView並且是通過removeAndRecycleView(view,recycler)方法移除的。他的作用是在需要新的HolderView時,精確匹配是不是剛剛移除的,如果是,就直接返回給RecyclerView展示,如果不是,那麼及時mCachedViews中有holderView實例,也不會返回,二十到mRecyclerPool中去找一個HolderView實例返回,重新綁定數據使用。
  4. 在mAttachedScrap、mCachedViews中的holderView都是精確匹配的,真正被標識爲廢棄的是存放在mRecyclerPool中的holderView。

需要注意的是,在mAttachedScrap和mCachedViews中拿到的holderView,因爲都是精確匹配的,所以都是直接使用,不會調用onBindViewHolder重新綁定數據,只有在mRecyclerPool中拿到的HolderView纔會重新綁定數據。所以只有在mCachedViews存在時,池子的使用效率是最高的,即來回滾動RecyclerView時。

當我們重寫LayoutManager時,有幾個函數需要注意:

  • public void detachAndScrapAttachedViews(@NonNull RecyclerView.Recycler recycler)
    僅在onLayoutChildren方法中使用,把當前屏幕上所有的HolderView與屏幕分離,存放在列表AttachedScrap中。
  • View childView = recycler.getViewForPosition(pos);
    用於向RecyclerView申請一個HolderView,至於這個holderView是從哪個池子中拿的,不需要關係,因爲該方法有自己的判斷 ,非常方便,正是這個函數爲我們實現了複用。
  • removeAndRecycleView(child, recycler);
    僅用在滾動的時候。在滾動時,我們需要把滾出屏幕的HolderView標記爲Removed,這個函數作用就是把不需要的HolderView標記爲Removed。在我們標記Removed以後,就會把這個HolderView移到mCachedViews中,如果mCachedViews已滿,就利用先進先出原則,將mCachedViews中老的holderView移到mREcyclerPool中,然後再把新的HolderView加入到mCachedViews中。
  • int getItemCount()
    得到的是Adapter中總共有多少數據要顯示,即總的item數
  • int getChildCount() 
    得到的是當前RecyclerView在顯示的item的個數,即當前屏幕中顯示的item數
  • View getChildAt(int index)
    獲取某個可見位置的View,即屏幕中顯示的某個View。index不是Adapter中的位置索引,而是當前屏幕上的位置索引。也就是說,獲取當前屏幕上顯示的第一個item的View應該用getChildAt(0),如果需要獲取屏幕上最後一個item的View,應該使用getChildAt(getChildCound()-1)
  • int getPosition(@NonNull View view)
    用於得到某個View在Adapter中的索引位置。拿到屏幕中顯示的最後一個View在Adapter中的索引:
    View lastView = getChildAt(getChildCount() - 1);
    int pos = getPosition(lastView);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章