RecyclerView 源码-缓存机制

查看RecyclerView 源码
避免忘记 特此记录

下面部分代码截取 LinearLayoutManager.javaRecyclerView.java
RecyclerView 的布局过程是由 LayoutManager 完成,在onLayoutChildren中 分为四步完成

// layout algorithm:
1) by checking children and other variables, find an anchor coordinate and an anchor item position.
2) fill towards start, stacking from bottom
3) fill towards end, stacking from top
4) scroll to fulfill requirements like stack from bottom.

LayoutManager 在调用填充方法 fill(recycler, mLayoutState, state, false)之前会调用 detachAndScrapAttachedViews(recycler) 将 RecyclerView 的childView 进行拆分,RecyclerView 拆分后的itemView会根据flag标记分别存入mChangedScrap 和 mAttachedScrap

//拆分RecyclerView 过程 会调用 scrapView 将itemView临时存储
detachAndScrapAttachedViews(recycler);

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("Called scrap view with an invalid view."
                        + " Invalid views cannot be reused from scrap, they should rebound from"
                       + " recycler pool." + exceptionLabel());
           }
           holder.setScrapContainer(this, false);
           mAttachedScrap.add(holder);
        } else {
           if (mChangedScrap == null) {
               mChangedScrap = new ArrayList<ViewHolder>();
           }
          holder.setScrapContainer(this, true);
          mChangedScrap.add(holder);
       }
}

在fill()方法中 不断循环layoutChunk() ,将View添加进RecyclerView
通过layoutState.next(recycler) 方法查找View

void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,
      LayoutState layoutState, LayoutChunkResult result) {
           //获取View入口
         View view = layoutState.next(recycler);
         if (view == null) {
         	//找不到View赋值结束状态 
         	 result.mFinished = true;
            return;
        }
 .....
	if (layoutState.mScrapList == null) {
	   if (mShouldReverseLayout == (layoutState.mLayoutDirection  == LayoutState.LAYOUT_START)) {
	         addView(view);
	   } else {
	         addView(view, 0);
	   }
	 } else {
	    if (mShouldReverseLayout == (layoutState.mLayoutDirection == LayoutState.LAYOUT_START)) {
	          addDisappearingView(view);
	     } else {
	          addDisappearingView(view, 0);
	      }
	 }
 .....
}

获取布局,并将索引指向下一个

	//在缓存类 Recycler 中获取到View
    View next(RecyclerView.Recycler recycler) {
         if (mScrapList != null) {
              return nextViewFromScrapList();
         }
         //调用 RecyclerView 中 getViewForPosition 方法
       	 final View view = recycler.getViewForPosition(mCurrentPosition);
         mCurrentPosition += mItemDirection;
         return view;
    }

开始查找View缓存的逻辑,RecyclerView是将ViewHolder缓存起来然后获取对应的itemView、
查找过程大致分为四个过程、如果都没有则会调用adapter的 onCreateViewHolder 创建

ViewHolder tryGetViewHolderForPositionByDeadline(int position, boolean dryRun, long deadlineNs) {
    // 0 先从  ArrayList<ViewHolder> mChangedScrap = null; 列表中取
    // 0) If there is a changed scrap, try to find from there
    if (mState.isPreLayout()) {
          holder = getChangedScrapViewForPosition(position);
          ......
     }
    // 1) Find by position from scrap/hidden list/cache
    // 1) 如果在mChangedScrap 中未找到,根据索引在 scrap/hidden list/cache 中查找
    if (holder == null) {
      	holder = getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);
          ....
     }
     if (holder == null) {
      // 2 根据itemId 和 type 从mChangedScrap ,mCachedViews中查找
      // 2) Find from scrap/cache via stable ids, if exists‘’
       	if (mAdapter.hasStableIds()) {
           holder = getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition),type, dryRun);
           ....
       	}
        if (holder == null && mViewCacheExtension != null) {
             final View view = mViewCacheExtension .getViewForPositionAndType(this, position, type);
             .....
             if (view != null) {
                 holder = getChildViewHolder(view);
           	}
      	}
     }
     // 3 在RecycledViewPool 中查找
     if (holder == null) { // fallback to pool
            holder = getRecycledViewPool().getRecycledView(type);
      }
      // 4 adapter createViewHolder 创建
     if (holder == null) {
	       holder = mAdapter.createViewHolder(RecyclerView.this, type);
      }
}

step 0 mChangedScrap 中根据position / id 查找

ViewHolder getChangedScrapViewForPosition(int position) {
   ....
   // find by position 遍历列表并从中找到ViewHolder
    for (int i = 0; i < changedScrapSize; i++) {
        final ViewHolder holder = mChangedScrap.get(i);
        if (!holder.wasReturnedFromScrap() && holder.getLayoutPosition() == position) {
            holder.addFlags(ViewHolder.FLAG_RETURNED_FROM_SCRAP);
             return holder;
        }
 	}
 	// find by id
	if (mAdapter.hasStableIds()) {
	     final int offsetPosition = mAdapterHelper.findPositionOffset(position);
	     if (offsetPosition > 0 && offsetPosition < mAdapter.getItemCount()) {
	          final long id = mAdapter.getItemId(offsetPosition);
	          for (int i = 0; i < changedScrapSize; i++) {
	          	 final ViewHolder holder = mChangedScrap.get(i);
	           	 if (!holder.wasReturnedFromScrap() && holder.getItemId() == id) {
	                 holder.addFlags(ViewHolder.FLAG_RETURNED_FROM_SCRAP);
	                 return holder;
	             }
	          }
	    }
	}
  return null;
}

step 1 在scrap/hidden list/cache 中依次查找
在 getScrapOrHiddenOrCachedHolderForPosition 方法中查找 ViewHolder 如果找到则 将ViewHolder缓存到mCachedViews中
如果没有找到则进行step2

//先从mAttachedScrap 中获取 并且更新flag
for (int i = 0; i < scrapCount; i++) {
    final ViewHolder holder = mAttachedScrap.get(i);
     if (!holder.wasReturnedFromScrap() && holder.getLayoutPosition() == position
           && !holder.isInvalid() && (mState.mInPreLayout || !holder.isRemoved())) {
       holder.addFlags(ViewHolder.FLAG_RETURNED_FROM_SCRAP);
       return holder;
     }
}
//如果 mAttachedScrap 中没有找到 则从 mHiddenViews 中查找
View view = mChildHelper.findHiddenNonRemovedView(position);
     if (view != null) {
      // This View is good to be used. We just need to unhide, detach and move to the
      // scrap list.
      final ViewHolder vh = getChildViewHolderInt(view);
     //改变view 的hide 状态
      mChildHelper.unhide(view); 
       int layoutIndex = mChildHelper.indexOfChild(view);
       if (layoutIndex == RecyclerView.NO_POSITION) {
           throw new IllegalStateException("layout index should not be -1 after "
            + "unhiding a view:" + vh + exceptionLabel());
       }
        mChildHelper.detachViewFromParent(layoutIndex);
        //将View存储在 mAttachedScrap 或者 mChangedScrap 中
        scrapView(view);
        vh.addFlags(ViewHolder.FLAG_RETURNED_FROM_SCRAP| ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST);
      return vh;
 }
 //最后在mCachedViews 中查找缓存过的ViewHolder 
// Search in our first-level recycled view cache.
	final int cacheSize = mCachedViews.size();
	 for (int i = 0; i < cacheSize; i++) {
	   final ViewHolder holder = mCachedViews.get(i);
	   ....
     	return holder;
     }
}

step 2 在scrap/cache 中根据itemId 和type 从mAttachedScrap 和 mCachedViews 查找

final int type = mAdapter.getItemViewType(offsetPosition);
 if (mAdapter.hasStableIds()) {
 //根据itemId 和type 从mAttachedScrap 和 mCachedViews 查找
    holder = getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition),type, dryRun);
       if (holder != null) {
           // update position
          holder.mPosition = offsetPosition;
          fromScrapOrHiddenOrCache = true;
        }
 }
if (holder == null && mViewCacheExtension != null) {
     // We are NOT sending the offsetPosition because LayoutManager does not know it.
     // ViewCacheExtension 抽象类中提供
      final View view = mViewCacheExtension.getViewForPositionAndType(this, position, type);
      if (view != null) {
     	 holder = getChildViewHolder(view);
      }
      .....
}

step 3 从RecycledViewPool 中获取

//从RecycledViewPool 中获取,RecycledViewPool 可用于多个不同RecyclerView共享item
if (holder == null) { // fallback to pool
    holder = getRecycledViewPool().getRecycledView(type);
    if (holder != null) {
       holder.resetInternal();
      if (FORCE_INVALIDATE_DISPLAY_LIST) {
          invalidateDisplayListInt(holder);
      }
   }
}

step 4 通过adapter 自行创建 ViewHolder

if (holder == 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);
      }
  }
}
    原文作者:叫我小马就好了
    原文地址: https://blog.csdn.net/wold0212/article/details/90906611
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞