RecyclerView缓存初步

本文参考自:【进阶】RecyclerView源码解析(二)——缓存机制 https://www.jianshu.com/p/e44961f8add5

—起因:由notifyItemRemoved引起的刷新,ui缓冲,加载holder。

  • 管理缓存的内部类:
    public final class Recycler {
    
        * 1.一级缓存:mAttachedScrap
        * 2.二级缓存:mCacheViews
        * 3.三级缓存:mViewCacheExtension       (自定义缓存)
        * 4.四级缓存:mRecyclerPool
    
            final ArrayList<RecyclerView.ViewHolder> mAttachedScrap = new ArrayList();
            ArrayList<RecyclerView.ViewHolder> mChangedScrap = null;
            final ArrayList<RecyclerView.ViewHolder> mCachedViews = new ArrayList();      
            RecyclerView.RecycledViewPool mRecyclerPool;
    }
    

     

  • recyclerview缓存holder的大致步骤

《RecyclerView缓存初步》 

  • 缓存入口 :
    final View view = recycler.getViewForPosition(mCurrentPosition);
  •  View getViewForPosition(int position, boolean dryRun) {
                return this.tryGetViewHolderForPositionByDeadline(position, dryRun, 9223372036854775807L).itemView;
            }
    
    
    RecyclerView.ViewHolder tryGetViewHolderForPositionByDeadline(int position, boolean dryRun, long deadlineNs) {
    ..........
    
    1. 默认为false,只有有动画的时候为true , holder 从Recycler类 mChangeScrap 中获取
         但是这个 并不在 正常的四级缓存中,,因为大多数时候都是false。
    
            if (RecyclerView.this.mState.isPreLayout()) {
                        holder = this.getChangedScrapViewForPosition(position);
                        fromScrapOrHiddenOrCache = holder != null;
                    }
    
    2.第一次正式获取缓存   //看名字 就知道 分三步  scrap hidden  cache
       holder = this.getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);
         
       RecyclerView.ViewHolder getScrapOrHiddenOrCachedHolderForPosition(int position, boolean dryRun) {
    
       **尝试从一级缓存mAttachedScrap 获取缓存
        for(cacheSize = 0; cacheSize < scrapCount; ++cacheSize) {
                    vh = (RecyclerView.ViewHolder)this.mAttachedScrap.get(cacheSize);
                    ......
                }
       **   。。。。有个hiddenView
    
            if (!dryRun) {
                //从HiddenView中获得,这里获得是View
                View view = mChildHelper.findHiddenNonRemovedView(position);
                if (view != null) {
                   
                    final ViewHolder vh = getChildViewHolderInt(view);
                    
                //添加到scrap中?
                    scrapView(view);
                   
                }
            }
       **尝试从二级缓存获取
           final int cacheSize = mCachedViews.size();
           for (int i = 0; i < cacheSize; i++) {
                final ViewHolder holder = mCachedViews.get(i);
              
                //holder是有效的,并且position相同
                if (!holder.isInvalid() && holder.getLayoutPosition() == position) {
                    if (!dryRun) {
                        mCachedViews.remove(i);
                    }
                    return holder;
                }
            }
    
    
    }

     《RecyclerView缓存初步》

 

  •  
2.第二次正式获取缓存  //从scrap cache  通过 id 获取

if (holder == null) {
                    .....
                    type = RecyclerView.this.mAdapter.getItemViewType(offsetPosition);
                    if (RecyclerView.this.mAdapter.hasStableIds()) {
                        holder = this.getScrapOrCachedViewForId(RecyclerView.this.mAdapter.getItemId(offsetPosition), type, dryRun);
                        ...
                    }

RecyclerView.ViewHolder getScrapOrCachedViewForId(long id, int type, boolean dryRun) {

 *** 尝试从一级缓存attachedScrap  获取
     for(i = count - 1; i >= 0; --i) {
                RecyclerView.ViewHolder holder = (RecyclerView.ViewHolder)this.mAttachedScrap.get(i);
                if (type == holder.getItemViewType()) {
                    holder.addFlags(ViewHolder.FLAG_RETURNED_FROM_SCRAP);
                    .....

                    if (!dryRun) {
                        this.mAttachedScrap.remove(i);
                        .....
                    }
                }
  ***尝试从二级缓存cacheView获取
        i = this.mCachedViews.size();
        for(int ix = i - 1; ix >= 0; --ix) {
                RecyclerView.ViewHolder holderx = (RecyclerView.ViewHolder)this.mCachedViews.get(ix);
                if (holderx.getItemId() == id) {
                    if (type == holderx.getItemViewType()) {
                        if (!dryRun) {
                            this.mCachedViews.remove(ix);
                        }
            }
}

 《RecyclerView缓存初步》

  •  第三次正式获取缓存     (自定义缓存  ,e)
  •  
  • 第四次正式获取缓存  —-是完全的针对pool 的  和之前的 性质不一样
holder = this.getRecycledViewPool().getRecycledView(type);

public static class RecycledViewPool {
    private static final int DEFAULT_MAX_SCRAP = 5;
    static class ScrapData {
        ArrayList<ViewHolder> mScrapHeap = new ArrayList<>();
        int mMaxScrap = DEFAULT_MAX_SCRAP;
      ....
    }
    SparseArray<ScrapData> mScrap = new SparseArray<>();
    ...
    // 可以看到 SparseArray 的 key 是ViewType,  value 是 ArrayList<ViewHolder>。
    public ViewHolder getRecycledView(int viewType) {
        final ScrapData scrapData = mScrap.get(viewType);
        if (scrapData != null && !scrapData.mScrapHeap.isEmpty()) {
            final ArrayList<ViewHolder> scrapHeap = scrapData.mScrapHeap;
            return scrapHeap.remove(scrapHeap.size() - 1);
        }
        return null;
    }
    ......
  }
  •  第五次“获取”缓存  —-当以上4步都没有得到 缓存的holder,通过自己创建holder
    holder = RecyclerView.this.mAdapter.createViewHolder(RecyclerView.this, type);

     

 

    原文作者:qq_41645066
    原文地址: https://blog.csdn.net/qq_41645066/article/details/83472769
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞