本文以通俗的語言,記錄在閱讀RecyclerView源碼時的一些心得🤔。
添加view的過程
- 在使用recyclerView的setAdapter方法設置adapter時,會調用RecyclerView的requestLayout()方法,進而執行measure、layout等生命方法;
- 何時添加的子view(adapter裏面的一堆):在RecyclerView執行layout時,實際會調用LayoutManager的onLayoutChildren()方法去layout子view,如LinearLayoutManager,方法堆棧:onLayoutChildren()->fill()->layoutChunk()。
- 滾動時如何判斷需要add一個子view:核心方法:updateLayoutState(),以向右滑動爲例:①拿到當前最左邊的view(getChildClosestToStart()),一般就是child0;②然後計算還可以向左滑動多遠的距離才需要add一個view,getDecoratedStart()方法:計算最左邊的子view在RecyclerView中的位置(getLeft()+margin)。經過計算之後可以知道:是否需要添加新的子view來填充RecyclerView。
View的複用
下面描述RecyclerView是如何對view進行復用的。
一、RecyclerView的緩存
- 一級緩存:mAttachedScrap
mAttachedScrap中的view不需要重新bindView。ScrapView主要用於對於屏幕內的ChildView的緩存,緩存中的ViewHolder不需要重新Bind,緩存時機是在onLayout的過程中,並且用完即清空,裏面的view只是被detach,不會被remove,在onLayout時會使用; - 二級緩存:mCacheViews
mCacheViews也不需要重新bind,裏面的view是被remove過的; - 三級緩存:mViewCacheExtension
- 四級緩存:mRecyclerPool
二、view查找過程
在RecyclerView的view不足時,需要addView,view的查找過程如下,一層層降級獲取可使用的view:
- 優先從mAttachedScrap列表中查找,查找的position必須和列表中某個holder的position完全一致,即:要查找的holder和該緩存裏面的某個holder達到完全一致的狀態;
- 從mCachedViews列表中查找,也需要position完全一致匹配。mCachedViews默認最大緩存爲2,當大於該值時,將holder緩存移至RecycledViewPool;
- mAdapter.hasStableIds()爲true時,否則轉4:從mAttachedScrap、mCachedViews列表中查找viewType相同的holder,在1、2都失敗的情況下,說明position完全匹配失敗,這時候需要找到viewType相同的holder緩存;
- 從RecycledViewPool裏面根據viewType查找緩存的holder。
說明:RecycledViewPool針對每一種viewType有一個緩衝池,池子大小默認爲5,當某一種viewType的holder在RecycledViewPool中的緩存數量大於最大值時,會被丟棄; - 緩存全部無法命中,則調用Adapter.createViewHolder新建holder。