/*** Remove a child view and recycle it using the given Recycler.** @param index Index of child to remove and recycle* @param recycler Recycler to use to recycle child*/publicvoidremoveAndRecycleViewAt(intindex,@NonNullRecyclerrecycler){finalViewview=getChildAt(index);removeViewAt(index);recycler.recycleView(view);}//LinearLayoutManager的recycleChildren方法privatevoidrecycleChildren(RecyclerView.Recyclerrecycler,intstartIndex,intendIndex){if(startIndex==endIndex){return;}if(DEBUG){Log.d(TAG,"Recycling "+Math.abs(startIndex-endIndex)+" items");}if(endIndex>startIndex){for(inti=endIndex-1;i>=startIndex;i--){removeAndRecycleViewAt(i,recycler);}}else{for(inti=startIndex;i>endIndex;i--){removeAndRecycleViewAt(i,recycler);}}}//LinearLayoutManager的recycleViewsFromStart方法//recycleViewsFromStart 和 recycleViewsFromEnd两个方法其实差不多只不过开始回收的位置不一样//如果向上滑动会调用recycleViewsFromStart 优先回收底部的view,如果向下滑动则相反privatevoidrecycleViewsFromStart(RecyclerView.Recyclerrecycler,intscrollingOffset,intnoRecycleSpace){if(scrollingOffset<0){if(DEBUG){Log.d(TAG,"Called recycle from start with a negative value. This might happen"+" during layout changes but may be sign of a bug");}return;}// ignore padding, ViewGroup may not clip children.finalintlimit=scrollingOffset-noRecycleSpace;finalintchildCount=getChildCount();if(mShouldReverseLayout){for(inti=childCount-1;i>=0;i--){Viewchild=getChildAt(i);//这是是判断是否可见来回收if(mOrientationHelper.getDecoratedEnd(child)>limit||mOrientationHelper.getTransformedEndWithDecoration(child)>limit){// stop hererecycleChildren(recycler,childCount-1,i);return;}}}else{for(inti=0;i<childCount;i++){Viewchild=getChildAt(i);if(mOrientationHelper.getDecoratedEnd(child)>limit||mOrientationHelper.getTransformedEndWithDecoration(child)>limit){// stop hererecycleChildren(recycler,0,i);return;}}}}privatevoidrecycleByLayoutState(RecyclerView.Recyclerrecycler,LayoutStatelayoutState){if(!layoutState.mRecycle||layoutState.mInfinite){return;}intscrollingOffset=layoutState.mScrollingOffset;intnoRecycleSpace=layoutState.mNoRecycleSpace;if(layoutState.mLayoutDirection==LayoutState.LAYOUT_START){recycleViewsFromEnd(recycler,scrollingOffset,noRecycleSpace);}else{recycleViewsFromStart(recycler,scrollingOffset,noRecycleSpace);}}
@NullableViewHoldertryGetViewHolderForPositionByDeadline(intposition,booleandryRun,longdeadlineNs){if(position<0||position>=mState.getItemCount()){thrownewIndexOutOfBoundsException("Invalid item position "+position+"("+position+"). Item count:"+mState.getItemCount()+exceptionLabel());}booleanfromScrapOrHiddenOrCache=false;ViewHolderholder=null;// 0) If there is a changed scrap, try to find from there//首先先从 changed scrap 中获取if(mState.isPreLayout()){holder=getChangedScrapViewForPosition(position);fromScrapOrHiddenOrCache=holder!=null;}// 1) Find by position from scrap/hidden list/cache//通过position 从scrap/hidden list/cache中获取if(holder==null){holder=getScrapOrHiddenOrCachedHolderForPosition(position,dryRun);if(holder!=null){if(!validateViewHolderForOffsetPosition(holder)){// recycle holder (and unscrap if relevant) since it can't be usedif(!dryRun){// we would like to recycle this but need to make sure it is not used by// animation logic etc.holder.addFlags(ViewHolder.FLAG_INVALID);if(holder.isScrap()){removeDetachedView(holder.itemView,false);holder.unScrap();}elseif(holder.wasReturnedFromScrap()){holder.clearReturnedFromScrapFlag();}recycleViewHolderInternal(holder);}holder=null;}else{fromScrapOrHiddenOrCache=true;}}}if(holder==null){finalintoffsetPosition=mAdapterHelper.findPositionOffset(position);if(offsetPosition<0||offsetPosition>=mAdapter.getItemCount()){thrownewIndexOutOfBoundsException("Inconsistency detected. Invalid item "+"position "+position+"(offset:"+offsetPosition+")."+"state:"+mState.getItemCount()+exceptionLabel());}finalinttype=mAdapter.getItemViewType(offsetPosition);// 2) Find from scrap/cache via stable ids, if exists//通过 stable id从 scrap/cache中获取if(mAdapter.hasStableIds()){holder=getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition),type,dryRun);if(holder!=null){// update positionholder.mPosition=offsetPosition;fromScrapOrHiddenOrCache=true;}}if(holder==null&&mViewCacheExtension!=null){// We are NOT sending the offsetPosition because LayoutManager does not// know it.finalViewview=mViewCacheExtension.getViewForPositionAndType(this,position,type);if(view!=null){holder=getChildViewHolder(view);if(holder==null){thrownewIllegalArgumentException("getViewForPositionAndType returned"+" a view which does not have a ViewHolder"+exceptionLabel());}elseif(holder.shouldIgnore()){thrownewIllegalArgumentException("getViewForPositionAndType returned"+" a view that is ignored. You must call stopIgnoring before"+" returning this view."+exceptionLabel());}}}//尝试从RecycledViewPool中获取if(holder==null){// fallback to poolif(DEBUG){Log.d(TAG,"tryGetViewHolderForPositionByDeadline("+position+") fetching from shared pool");}holder=getRecycledViewPool().getRecycledView(type);if(holder!=null){holder.resetInternal();if(FORCE_INVALIDATE_DISPLAY_LIST){invalidateDisplayListInt(holder);}}}if(holder==null){longstart=getNanoTime();if(deadlineNs!=FOREVER_NS&&!mRecyclerPool.willCreateInTime(type,start,deadlineNs)){// abort - we have a deadline we can't meetreturnnull;}//都没有获取到//创建viewholderholder=mAdapter.createViewHolder(RecyclerView.this,type);if(ALLOW_THREAD_GAP_WORK){// only bother finding nested RV if prefetchingRecyclerViewinnerView=findNestedRecyclerView(holder.itemView);if(innerView!=null){holder.mNestedRecyclerView=newWeakReference<>(innerView);}}longend=getNanoTime();mRecyclerPool.factorInCreateTime(type,end-start);}}//...returnholder;}