RecycleView的四级缓存

Recycler 中ArrayList<ViewHolder> mAttachedScrap 是缓存RecycleView做动画时,被detach的viewHolder, ArrayList<ViewHolder> mChangedScrap 缓存刷新时,被detach的viewHolder ,ArrayList<ViewHolder> mCachedViews  以及Viewholder的缓存,最多两个,

RecycledViewPool 缓存池View(这个默认5个),当mCachedView装满时,放入这个RecycledViewPool中

在recycleViewHolderInternal中,当mCachedViews的大小超过两个时候,再来一个viewHolder时,会把新的添加进去,给第0个放到RecycledViewPool中:

if (cachedViewSize >=mViewCacheMax && cachedViewSize >0) {

recycleCachedViewAt(0);

    cachedViewSize--;

}

在recycleCachedViewAt(0);

ViewHolder viewHolder =mCachedViews.get(cachedViewIndex);

这个cachedViewIndex就是0,取出mCachedViews第一个,从mCachedViews中移除

addViewHolderToRecycledViewPool(viewHolder, true);

mCachedViews.remove(cachedViewIndex);

在addViewHolderToRecycledViewPool(@NonNull ViewHolder holder, boolean dispatchRecycled)这个里面通过调用getRecycledViewPool().putRecycledView(holder);给ViewHolder中的View添加到mCachedViews

在ViewHoldergetScrapOrHiddenOrCachedHolderForPosition(int position, boolean dryRun)中,调用scrapView(view);

在scrapView(view);中

final ViewHolder holder =getChildViewHolderInt(view);

if (holder.hasAnyOfTheFlags(ViewHolder.FLAG_REMOVED | ViewHolder.FLAG_INVALID)

|| !holder.isUpdated() || canReuseUpdatedViewHolder(holder)) {

holder.setScrapContainer(this, false);

    mAttachedScrap.add(holder);  //添加动画ViewHolder

}else {

if (mChangedScrap ==null) {

mChangedScrap =new ArrayList();

    }

holder.setScrapContainer(this, true);

    mChangedScrap.add(holder); //添加刷新ViewHolder

}

那么RecycleView是怎样进行ViewHolder的回收的呢,在LinearLayoutManager中:

int fill(RecyclerView.Recycler recycler, LayoutState layoutState,

RecyclerView.State state,boolean stopOnFocusable) {

layoutChunk(recycler, state, layoutState, layoutChunkResult);

      recycleByLayoutState(recycler, layoutState);}

在recycleByLayoutState(recycler, layoutState);这这个里面

private void recycleByLayoutState(RecyclerView.Recycler recycler, LayoutState layoutState) {if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) {

recycleViewsFromEnd(recycler, layoutState.mScrollingOffset);

}else {

recycleViewsFromStart(recycler, layoutState.mScrollingOffset);

}

}

先看一下recycleViewsFromStart(recycler, layoutState.mScrollingOffset);这个方法

private void recycleViewsFromStart(RecyclerView.Recycler recycler,int dt) {

               recycleChildren(recycler, childCount -1, i);

}

在recycleChildren中进行了View的回收

private void recycleChildren(RecyclerView.Recycler recycler,int startIndex,int endIndex) {

if (endIndex > startIndex) {

for (int i = endIndex -1; i >= startIndex; i--) {

removeAndRecycleViewAt(i, recycler);

}

}else {

for (int i = startIndex; i > endIndex; i--) {

removeAndRecycleViewAt(i, recycler);

}

}

}


public void removeAndRecycleViewAt(int index, Recycler recycler) {

final View view = getChildAt(index);

removeViewAt(index);

recycler.recycleView(view);

}

public void recycleView(View view) {

   ViewHolder holder =getChildViewHolderInt(view);

if (holder.isTmpDetached()) {

removeDetachedView(view,false);

}

recycleViewHolderInternal(holder);

}

在recycleViewHolderInternal中,当mCachedViews的大小超过两个时候,再来一个viewHolder时,会把新的添加进去,给第0个放到RecycledViewPool中:

void recycleViewHolderInternal(ViewHolder holder) {


            int cachedViewSize =mCachedViews.size();

if (cachedViewSize >=mViewCacheMax && cachedViewSize >0) {

recycleCachedViewAt(0);

cachedViewSize--;

}

int targetCacheIndex = cachedViewSize;


if (!cached) {

//将回收的View放入到RecycleViewPool中

addViewHolderToRecycledViewPool(holder,true);

recycled =true;

}

}

void addViewHolderToRecycledViewPool(ViewHolder holder,boolean dispatchRecycled) {

clearNestedRecyclerViewIfNotNested(holder);

holder.itemView.setAccessibilityDelegate(null);

if (dispatchRecycled) {

dispatchViewRecycled(holder);

}

holder.mOwnerRecyclerView =null;

getRecycledViewPool().putRecycledView(holder);

}

//使用adapter回收ViewHolder

void dispatchViewRecycled(ViewHolder holder) {

if (mRecyclerListener !=null) {

mRecyclerListener.onViewRecycled(holder);

}

if (mAdapter !=null) {

mAdapter.onViewRecycled(holder);

}

if (mState !=null) {

mViewInfoStore.removeViewHolder(holder);

}

if (DEBUG) Log.d(TAG,"dispatchViewRecycled: " + holder);

}

public void putRecycledView(ViewHolder scrap) {

final int viewType = scrap.getItemViewType();

final ArrayList scrapHeap = getScrapDataForType(viewType).mScrapHeap;

if (mScrap.get(viewType).mMaxScrap <= scrapHeap.size()) {

return;

}


scrap.resetInternal();

scrapHeap.add(scrap);

}

SparseArray类型的mScrap中添加了以viewType为key,scrapData为value的对象。mScrap是RecycledViewPool中维护的一个SparseArray结构的map集合。回收来的东西放到了这里。

private ScrapData getScrapDataForType(int viewType) {

ScrapData scrapData =mScrap.get(viewType);

if (scrapData ==null) {

scrapData =new ScrapData();

mScrap.put(viewType, scrapData);

}

return scrapData;

}


RecycleView怎样进行复用

void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,

LayoutState layoutState, LayoutChunkResult result) {

View view = layoutState.next(recycler);

if (layoutState.mScrapList ==null) {

if (mShouldReverseLayout == (layoutState.mLayoutDirection

            == LayoutState.LAYOUT_START)) {

addView(view);//添加view

}else {

addView(view,0);//添加view

}

}else {

if (mShouldReverseLayout == (layoutState.mLayoutDirection

            == LayoutState.LAYOUT_START)) {

addDisappearingView(view);

}else {

addDisappearingView(view,0);

}

}

measureChildWithMargins(view,0,0);//测量子view

layoutDecoratedWithMargins(view, left, top, right, bottom);//布局子view

}

//获取要布局的下一个元素的视图

View next(RecyclerView.Recycler recycler) {

if (mScrapList !=null) {

return nextViewFromScrapList();

}

final View view = recycler.getViewForPosition(mCurrentPosition);

mCurrentPosition +=mItemDirection;

return view;

}

在recyclerView中根据position获得视图

public View getViewForPosition(int position) {

return getViewForPosition(position,false);

}

View getViewForPosition(int position,boolean dryRun) {

return tryGetViewHolderForPositionByDeadline(position, dryRun,FOREVER_NS).itemView;

}


ViewHolder tryGetViewHolderForPositionByDeadline(int position,

boolean dryRun,long deadlineNs) {

ViewHolder holder =null;

// 0) If there is a changed scrap, try to find from there

if (mState.isPreLayout()) {

//通过position从Recycler中的mChangedScrap寻找viewHolder

holder = getChangedScrapViewForPosition(position);

fromScrapOrHiddenOrCache = holder !=null;

}

if (holder ==null) {

//根据position从scrap或隐藏的view,或缓存中寻找view

holder = getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);

}

if (holder ==null) {

final int type =mAdapter.getItemViewType(offsetPosition);

// 2) Find from scrap/cache via stable ids, if exists

    if (mAdapter.hasStableIds()) {

//通过id从scrap或者mCacherView中获取viewHolder

holder = getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition),

type, dryRun);

}

if (holder ==null &&mViewCacheExtension !=null) {

   final View view =mViewCacheExtension

            .getViewForPositionAndType(this, position, type);

if (view !=null) {

//通过childe获取viewHolder

holder = getChildViewHolder(view);

}

}

//从RecyclerViewRool池中获取

holder = getRecycledViewPool().getRecycledView(type);

if (holder !=null) {

holder.resetInternal();

if (FORCE_INVALIDATE_DISPLAY_LIST) {

invalidateDisplayListInt(holder);

}

if (holder ==null) {

long start = getNanoTime();

if (deadlineNs !=FOREVER_NS

            && !mRecyclerPool.willCreateInTime(type, start, deadlineNs)) {

// abort - we have a deadline we can't meet

        return null;

}

//缓存中获取不到viewholder,就自己创建viewHolder

holder =mAdapter.createViewHolder(RecyclerView.this, type);

}

}

}

}

recyclerView用了四级缓存,mAttachedScrap是第一缓存,根据position或者id从mAttachedScrap获取viewHolder,第二级缓存就是从mCachedViews中获取viewHolder,第三级缓存是自定义缓存,通过调用getChildViewHolder获取,第四级缓存是从RecyclerViewPool中获取,当所有的缓存中都获取不到的时候,就自己创建viewHolder

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容