RecyclerView复用回收机制

本文深入探讨了RecyclerView的缓存系统,包括Recycler的组成、`tryGetViewHolderForPositionByDeadline`方法的五个步骤,以及mAttachedScrap和mCachedViews的使用。文章还分析了mAttachedScrap何时存储和清除列表数据,并讨论了RecyclerView的回收机制。此外,提到了mCachedViews的默认最大缓存数以及如何修改这一数值。
摘要由CSDN通过智能技术生成
Recycler组成

RecyclerView的缓存主要委托给了Recycler,先了解下组成

public final class Recycler {
   
    final ArrayList<RecyclerView.ViewHolder> mAttachedScrap = new ArrayList();
    ArrayList<RecyclerView.ViewHolder> mChangedScrap = null;
    final ArrayList<RecyclerView.ViewHolder> mCachedViews = new ArrayList();
    private final List<RecyclerView.ViewHolder> mUnmodifiableAttachedScrap;
    private int mRequestedCacheMax;
    int mViewCacheMax;
    RecyclerView.RecycledViewPool mRecyclerPool;
    private RecyclerView.ViewCacheExtension mViewCacheExtension;
    static final int DEFAULT_CACHE_SIZE = 2;
    //...
    }
    * 1.一级缓存:mAttachedScrap
    * 2.二级缓存:mCacheViews
    * 3.三级缓存:mViewCacheExtension
    * 4.四级缓存:mRecyclerPool

在RecyclerView的绘制流程中分析过,layoutManager会在layoutChunk方法中对view进行获取添加测量等操作,如下所示

//LinerLayoutManager.java
void layoutChunk(Recycler recycler, State state, LinearLayoutManager.LayoutState layoutState, LinearLayoutManager.LayoutChunkResult result) {
   
     View view = layoutState.next(recycler);
     // 执行addView
     // 测量view
}
//LinearLayoutManager.LayoutState
View next(Recycler recycler) {
   
	// mScrapList初始化为空,且仅在layoutForPredictiveAnimations被赋值,执行完后又被设置为null
    if (this.mScrapList != null) {
   
        return this.nextViewFromScrapList();
    } else {
   
    	// * 进入该分支
        View view = recycler.getViewForPosition(this.mCurrentPosition);
        this.mCurrentPosition += this.mItemDirection;
        return view;
    }
}
//RecyclerView.Recycler
@NonNull
public View getViewForPosition(int position) {
   
    return this.getViewForPosition(position, false);
}

View getViewForPosition(int position, boolean dryRun) {
   
    return this.tryGetViewHolderForPositionByDeadline(position, dryRun, 9223372036854775807L).itemView;
}
tryGetViewHolderForPositionByDeadline

该方法为获取缓存viewHolder核心方法

//RecyclerView.Recycler
@Nullable
RecyclerView.ViewHolder tryGetViewHolderForPositionByDeadline(int position, boolean dryRun, long deadlineNs) {
   
    if (position >= 0 && position < RecyclerView.this.mState.getItemCount()) {
   
        boolean fromScrapOrHiddenOrCache = false;
        RecyclerView.ViewHolder holder = null;
        //[0] 从changed Scrap获取holder
        if (RecyclerView.this.mState.isPreLayout()) {
   
        	//preLayout默认是false,只有有动画的时候才为true?
            holder = this.getChangedScrapViewForPosition(position);
            fromScrapOrHiddenOrCache = holder != null;
        }
		//[1] 从scrap中获取holder
        if (holder == null) {
   
            holder = this.getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);
            if (holder != null) {
   
            	// 检查该holder是否与holder对应postion
                if (!this.validateViewHolderForOffsetPosition(holder)) {
   
                	// 如果信息不符
                    if (!dryRun) {
   
                        holder.addFlags(4);
                       	// 从scrap移除
                        if (holder.isScrap()) {
   
                            RecyclerView.this.removeDetachedView(holder.itemView, false);
                            holder.unScrap();
                        } else if (holder.wasReturnedFromScrap()) {
   
                            holder.clearReturnedFromScrapFlag();
                        }
						// 将该holder放入mCachedViews或者mRecyclerPool中
                        this.recycleViewHolderInternal(holder);
                    }
					//设置为空
                    holder = null;
                } else {
   
                    fromScrapOrHiddenOrCache = true;
                }
            }
        }

        int offsetPosition;
        int type;
        if (holder == null) {
   
            offsetPosition = RecyclerView.this.mAdapterHelper.findPositionOffset(position);
            if (offsetPosition < 0 || offsetPosition >= RecyclerView.this.mAdapter.getItemCount()) {
   
                throw new IndexOutOfBoundsException("Inconsistency detected. Invalid item position " + position + "(offset:" + offsetPosition + ")." + "state:" + RecyclerView.this.mState.getItemCount() + RecyclerView.this.exceptionLabel());
            }

            type = RecyclerView.this.mAdapter.getItemViewType(offsetPosition);
            if (RecyclerView.this.mAdapter.hasStableIds()) {
   
                holder = this.getScrapOrCachedViewForId(RecyclerView.this.mAdapter.getItemId(offsetPosition), type, dryRun);
                if (holder != null) {
   
                    holder.mPosition = offsetPosition;
                    fromScrapOrHiddenOrCache = true;
                }
            }
			// 自定义缓存
            if (holder == null && this.mViewCacheExtension != null) {
   
                View view = this.mViewCacheExtension.getViewForPositionAndType(this, position, type);
                if (view != null) {
   
                    holder = RecyclerView.this.getChildViewHolder(view);
                    if (holder == null) {
   
                        throw new IllegalArgumentException("getViewForPositionAndType returned a view which does not have a ViewHolder" + RecyclerView.this.exceptionLabel());
                    }

                    if (holder.shouldIgnore()) {
   
                        throw new IllegalArgumentException("getViewForPositionAndType returned a view that is ignored. You must call stopIgnoring before returning this view." + RecyclerView.this.exceptionLabel());
                    }
                }
            }
			// 从缓存池中获取
            if (holder == null) {
   
                holder = this.getRecycledViewPool().getRecycledView(type);
                if (holder != null) {
   
                    holder.resetInternal();
                    if (RecyclerView.FORCE_INVALIDATE_DISPLAY_LIST) {
   
                        this.invalidateDisplayListInt(holder);
                    }
                }
            }
			// 创建
            if (holder == null) {
   
                long start = RecyclerView.this.getNanoTime();
                if (deadlineNs != 9223372036854775807L && !this.mRecyclerPool.willCreateInTime(type, start, deadlineNs)) {
   
                    return null;
                }

                holder = RecyclerView.this.mAdapter.createViewHolder(RecyclerView.this, type
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值