Android四级缓存,RecyclerView的缓存真是4级吗?

网上的大多数博客都是认为RecyclerView是4级缓存,但真的是4级缓存吗?知道我看了源码,才发现,RecyclerView做的远远不止4级缓存,当然是根据LayoutManager不同,缓存实现也不同,本文主要分析最最常用的LinearLayoutManager。

写的有点乱,以后整理吧

RecyclerView复用过程

RecyclerView的中的缓存复用是由内部类Recycler来维护的,在RecyclerView.Adapter调用onCreateViewHolder来创建ViewHolder,这时就开始了利用缓存机制;

这里是以LinearLayoutManager为例,其他也差不多,只是一些细节不一样;

先看下调用流程吧,否则直接看缓存,也不知道什么时候调用的:

fc51d94bdd49

RecyclerView.png

可以看到,RecyclerView的在onMeasure时,就将item所有的操作都交给了LayoutManager,并在创建ViewHolder时,将缓存复用机制交给了RecyclerView内部类Recycler,Recycler的tryGetViewHolderForPositionByDeadline方法内,实现了所有的复用机制;

缓存实现

Recycler :缓存机制的管理类

fc51d94bdd49

Recycler.png

public final class Recycler {

//主要由void scrapView(View view)来处理, 仍旧绑定在RecyclerView上,但是能rebinding和reuse;

final ArrayList mAttachedScrap = new ArrayList<>();

ArrayList mChangedScrap = null;

final ArrayList mCachedViews = new ArrayList();

private final List mUnmodifiableAttachedScrap = Collections.unmodifiableList(mAttachedScrap);

RecycledViewPool mRecyclerPool;

private ViewCacheExtension mViewCacheExtension;

}

从代码里这来看,里面就有4个集合外加一个RecycledViewPool和一个ViewCacheExtension,所以远不止4级缓存;

缓存的实现

接下来我们详细看下复用机制的实现:

其实在LayoutState的next方法中就有一层复用,mScrapList实际就是mUnmodifiableAttachedScrap,这个调用是在onLayoutChildren最后的layoutForPredictiveAnimations的方法中,做动画时,直接去拿mUnmodifiableAttachedScrap中的itemView;

否则才是真正的去创建View;

View next(RecyclerView.Recycler recycler) {

if (mScrapList != null) {

return nextViewFromScrapList();

}

final View view = recycler.getViewForPosition(mCurrentPosition);

mCurrentPosition += mItemDirection;

return view;

getViewForPosition中主要调用tryGetViewHolderForPositionByDeadline方法:

ViewHolder tryGetViewHolderForPositionByDeadline(int position, boolean dryRun, long deadlineNs) {

RecyclerView.ViewHolder holder = null;

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

// isPreLayout的条件是在RecyclerView的onMeasure中,如果不是自动测量,adapter大小不是固定的,或者是自定义onMeasure

//如果只是changed,就会进入到getChangedScrapViewForPosition,里面主要从mChangedScrap取数据;

if (mState.isPreLayout()) {

//里面主要是从mChangedScrap中找

holder = getChangedScrapViewForPosition(position);

}

// 1) Find by position from scrap/hidden list/cache

if (holder == null) {

// 里面主要从mAttachedScrap和ChildHelper的mHiddenViews还有mCachedViews中查找

//这里面是确切的匹配,里面各种状态必须完全一致,拿出来的,不需要经过rebinding

holder = getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);

}

if (holder == null) {

final int offsetPosition = mAdapterHelper.findPositionOffset(position);

final int type = mAdapter.getItemViewType(offsetPosition);

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

//hasStableIds默认是true,在adapter的构造中赋值的

if (mAdapter.hasStableIds()) {

//利用Position找不到时,再用id和type匹配,拿出来之后需要rebinding

holder = getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition), type, dryRun);

}

// 用户自定义扩展缓存

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

// We are NOT sending the offsetPosition because LayoutManager does not

// know it.

final View view = mViewCacheExtension.getViewForPositionAndType(this, position, type);

if (view != null) {

holder = getChildViewHolder(view);

}

}

//RecycledView复用池

if (holder == null) { // fallback to pool

holder = getRecycledViewPool().getRecycledView(type);

}

// 创建新的Item

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;

}

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

if (ALLOW_THREAD_GAP_WORK) {

// only bother finding nested RV if prefetching

RecyclerView innerView = findNestedRecyclerView(holder.itemView);

if (innerView != null) {

holder.mNestedRecyclerView = new WeakReference<>(innerView);

}

}

}

}

return holder;

}

在LayoutState中的next方法中还有一层缓存,利用的mScrapList ,其实mScrapList 就是mUnmodifiableAttachedScrap

View next(RecyclerView.Recycler recycler) {

if (mScrapList != null) {

return nextViewFromScrapList();

}

final View view = recycler.getViewForPosition(mCurrentPosition);

mCurrentPosition += mItemDirection;

return view;

}

private View nextViewFromScrapList() {

final int size = mScrapList.size();

for (int i = 0; i < size; i++) {

final View view = mScrapList.get(i).itemView;

final RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) view.getLayoutParams();

if (lp.isItemRemoved()) {

continue;

}

if (mCurrentPosition == lp.getViewLayoutPosition()) {

assignPositionFromScrapList(view);

return view;

}

}

return null;

}

这里面涉及到2个缓存mAttachedScrap和mChangedScrap,可以看到这2个缓存的定义了

void scrapView(View view) {

final ViewHolder holder = getChildViewHolderInt(view);

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

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

if (holder.isInvalid() && !holder.isRemoved() && !mAdapter.hasStableIds()) {

throw new IllegalArgumentException(...);

}

holder.setScrapContainer(this, false);

mAttachedScrap.add(holder);

} else {

if (mChangedScrap == null) {

mChangedScrap = new ArrayList();

}

holder.setScrapContainer(this, true);

mChangedScrap.add(holder);

}

}

总结

写的有些乱,代码太多了,都很重要,建议自己再看一遍

fc51d94bdd49

缓存机制.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值