以下文章来源于星际码仔 ,作者椎锋陷陈
用浅显语言&生动动图,将复杂技术简单呈现。
从而达到的改善性能、提升应用响应能力、降低功耗的效果。而要了解其中的工作原理,我们还得回到RecyclerView是如何构建动态列表的这一步。
实际上,这也是RecyclerView从缓存中查找最佳匹配ViewHolder对象时所遵循的优先级顺序。而真正负责执行这项查找工作的,则是RecyclerView类中一个被称为「回收者」的内部类——Recycler。
/**
* ...
* When {@link Recycler#getViewForPosition(int)} is called, Recycler checks attached scrap and
* first level cache to find a matching View. If it cannot find a suitable View, Recycler will
* call the {@link #getViewForPositionAndType(Recycler, int, int)} before checking
* {@link RecycledViewPool}.
*
* 当调用getViewForPosition(int)方法时,Recycler会检查attached scrap和一级缓存(指的是mCachedViews)以找到匹配的View。
* 如果找不到合适的View,Recycler会先调用ViewCacheExtension的getViewForPositionAndType(RecyclerView.Recycler, int, int)方法,再检查RecycledViewPool对象。
* ...
*/
public abstract static class ViewCacheExtension {
...
}
public final class Recycler {
...
/**
* Attempts to get the ViewHolder for the given position, either from the Recycler scrap,
* cache, the RecycledViewPool, or creating it directly.
*
* 尝试通过从Recycler scrap缓存、RecycledViewPool查找或直接创建的形式来获取指定位置的ViewHolder。
* ...
*/
@Nullable
ViewHolder tryGetViewHolderForPositionByDeadline(int position,
boolean dryRun, long deadlineNs) {
if (mState.isPreLayout()) {
// 0 尝试从mChangedScrap中获取ViewHolder对象
holder = getChangedScrapViewForPosition(position);
...
}
if (holder == null) {
// 1.1 尝试根据position从mAttachedScrap或mCachedViews中获取ViewHolder对象
holder = getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);
...
}
if (holder == null) {
...
final int type = mAdapter.getItemViewType(offsetPosition);
if (mAdapter.hasStableIds()) {
// 1.2 尝试根据id从mAttachedScrap或mCachedViews中获取ViewHolder对象
holder = getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition),
type, dryRun);
...
}
if (holder == null && mViewCacheExtension != null) {
// 2 尝试从mViewCacheExtension中获取ViewHolder对象
final View view = mViewCacheExtension
.getViewForPositionAndType(this, position, type);
if (view != null) {
holder = getChildViewHolder(view);
...
}
}
if (holder == null) { // fallback to pool
// 3 尝试从mRecycledViewPool中获取ViewHolder对象
holder = getRecycledViewPool().getRecycledView(type);
...
}
if (holder == null) {
// 4.1 回调createViewHolder方法创建ViewHolder对象及其关联的视图
holder = mAdapter.createViewHolder(RecyclerView.this, type);
...
}
}
if (mState.isPreLayout() && holder.isBound()) {
...
} else if (!holder.isBound() || holder.needsUpdate() || holder.isInvalid()) {
...
// 4.1 回调bindViewHolder方法提取数据填充ViewHolder的视图内容
bound = tryBindViewHolderByDeadline(holder, offsetPosition, position, deadlineNs);
}
...
return holder;
}
...
}
final ArrayList<ViewHolder> mAttachedScrap = new ArrayList<>();
ArrayList<ViewHolder> mChangedScrap = null;
boolean canReuseUpdatedViewHolder(ViewHolder viewHolder) {
return mItemAnimator == null || mItemAnimator.canReuseUpdatedViewHolder(viewHolder,
viewHolder.getUnmodifiedPayloads());
}
public boolean canReuseUpdatedViewHolder(@NonNull ViewHolder viewHolder,
@NonNull List<Object> payloads) {
return canReuseUpdatedViewHolder(viewHolder);
}
public boolean canReuseUpdatedViewHolder(@NonNull ViewHolder viewHolder) {
return true;
}
recyclerView.itemAnimator = null
final ArrayList<ViewHolder> mCachedViews = new ArrayList<ViewHolder>();
int mViewCacheMax = DEFAULT_CACHE_SIZE;
static final int DEFAULT_CACHE_SIZE = 2;
recyclerView.layoutManager?.isItemPrefetchEnabled = false
public static class RecycledViewPool {
private static final int DEFAULT_MAX_SCRAP = 5;
static class ScrapData {
final ArrayList<ViewHolder> mScrapHeap = new ArrayList<>();
int mMaxScrap = DEFAULT_MAX_SCRAP;
long mCreateRunningAverageNs = 0;
long mBindRunningAverageNs = 0;
}
SparseArray<ScrapData> mScrap = new SparseArray<>();
...
}
以上的就是RecyclerView缓存复用机制的核心内容了。
最后推荐一下我做的网站,玩Android: wanandroid.com ,包含详尽的知识体系、好用的工具,还有本公众号文章合集,欢迎体验和收藏!
推荐阅读:
扫一扫 关注我的公众号
如果你想要跟大家分享你的文章,欢迎投稿~
┏(^0^)┛明天见!