总结一下:Recycler就是一个不折不扣的回收站,在里面针对ViewHolder进行一系列回收站应进行的操作。
下一个看adapter类或者rvpool类
// mAttachedScrap是你recycler类中当前维护的废品吗
final ArrayList<ViewHolder>mAttachedScrap = new ArrayList<>();
// mChangedScrap我猜测是将被遣送去重用的viewholder集合
ArrayList<ViewHolder> mChangedScrap =null;
//被缓存的views?
final ArrayList<ViewHolder> mCachedViews= new ArrayList<ViewHolder>();
// 把mAttachedScrap设置成只读(不可修改)的集合,牛
private final List<ViewHolder>
mUnmodifiableAttachedScrap =Collections.unmodifiableList(mAttachedScrap);
//把被请求的缓存最大值和view缓存最大值设为默认值2
private int mRequestedCacheMax = DEFAULT_CACHE_SIZE;
int mViewCacheMax = DEFAULT_CACHE_SIZE;
//维护一个RecycledViewPool的实例
RecycledViewPool mRecyclerPool;
//维护ViewCacheExtension的实例
private ViewCacheExtensionmViewCacheExtension;
static final int DEFAULT_CACHE_SIZE = 2;
//把报废的views从Recycler中清除出去,recyclerview pool中包含着的与recyclerview脱离联系的views将会被留存下来
public void clear() {
mAttachedScrap.clear();
recycleAndClearCachedViews();
}
//设置被分离的、可用的views的最大数量,我们应该为了接下来的使用而保留的
public void setViewCacheSize(int viewCount){
mRequestedCacheMax = viewCount;
updateViewCacheSize();
}
void updateViewCacheSize() {
//更新缓存大小
int extraCache = mLayout != null ? mLayout.mPrefetchMaxCountObserved :0;
mViewCacheMax = mRequestedCacheMax + extraCache;
//这里如果你更新了以后,发现已有的缓存比最大缓存数量大,那么就要把多余的部分回收掉。
// first, try the views that can be recycled
for (int i = mCachedViews.size() - 1;
i >= 0 &&mCachedViews.size() > mViewCacheMax; i--) {
recycleCachedViewAt(i);
}
}
public List<ViewHolder>getScrapList() {
return mUnmodifiableAttachedScrap;
}
//验证ViewHolder的偏移位置(个人感觉神头鬼脸,看不太懂他想用这个方法干什么)
//是getViewForPosition的辅助方法
检查一个被给予的ViewHolder是否可以被用来作为被分享(共享)的位置
booleanvalidateViewHolderForOffsetPosition(ViewHolder holder) {
// if it is a removed holder, nothing to verify since we cannot askadapter anymore
// if it is not removed, verify the type and id.
//如果这个holder已经被移除了,我们不能去校验它因为我们什么都不能询问Adapter了
//如果这个holder没有被移除,校验这个holder的类型和id
if (holder.isRemoved()) {
if (DEBUG &&!mState.isPreLayout()) {
throw newIllegalStateException("should not receive a removed view unless it"
+ " is prelayout");
}
return mState.isPreLayout();
}
if (holder.mPosition < 0 || holder.mPosition >=mAdapter.getItemCount()) {
throw newIndexOutOfBoundsException("Inconsistency detected. Invalid view holder"
+ "adapterposition" + holder);
}
//pre-layout到底是个啥概念?
if (!mState.isPreLayout()) {
// don't check type if it ispre-layout.
final int type =mAdapter.getItemViewType(holder.mPosition);
if (type !=holder.getItemViewType()) {
return false;
}
}
//稳定的id,难道还有不稳定的id?要不要把这么简单的控件写的这么云里雾里?这还是优雅的写法吗?
if (mAdapter.hasStableIds()) {
return holder.getItemId() ==mAdapter.getItemId(holder.mPosition);
}
return true;
}
//试图绑定视图,并考虑相关的时间信息.如果绑定视图的截止期限不等于FOREVER_NS,这个方法或许不能去绑定,并且会返回错误
private booleantryBindViewHolderByDeadline(ViewHolder holder, int offsetPosition,
int position, long deadlineNs){
//哦,不错,在这里把这个recyclerView赋给holder,昨天有看到过
holder.mOwnerRecyclerView = RecyclerView.this;
final int viewType = holder.getItemViewType();
long startBindNs = getNanoTime();//获取java虚拟机中高精度的时间
if (deadlineNs != FOREVER_NS
&&!mRecyclerPool.willBindInTime(viewType, startBindNs, deadlineNs)) {
// abort(退出) - we have a deadline we can't meet
return false;
}
//哦,不错,看到了熟悉的绑定方法,而且参数都是一样的
mAdapter.bindViewHolder(holder, offsetPosition);
long endBindNs = getNanoTime();
//这里是把差值简单记录一下吗
mRecyclerPool.factorInBindTime(holder.getItemViewType(), endBindNs -startBindNs);
//连接可访问性代表?
attachAccessibilityDelegate(holder.itemView);
//这个prelayout还是没能理解
if (mState.isPreLayout()) {
holder.mPreLayoutPosition =position;
}
return true;
}
//绑定所给的view到指定的位置,这个view可以是先前通过getViewForPosition(int)方法被检索的,或者是被Adapter#onCreateViewHolder(ViewGroup, int)方法创建的。大多数情况,一个LayoutManager应该通过getViewForPosition(int)方法来获取他的views并且让recyclerView来处理高速缓存。这是一个辅助方法用于一个想要去处理它自己的回收逻辑的LayoutManager。注意,getViewForPosition(int)方法已经绑定了view到这个位置上所以你不需要去调用这个方法除非你想要去绑定这个view到另一个位置。
public void bindViewToPosition(View view,int position) {
//这个getchild让我,想不穿。
ViewHolder holder = getChildViewHolderInt(view);
if (holder == null) {
throw newIllegalArgumentException("The view does not have a ViewHolder. Youcannot"
+ " pass arbitraryviews to this method, they should be created by the "
+ "Adapter");
}
//竟然还有AdapterHelper和ChildHelper这两个类,我tm。。还有光给一个位置怎么找偏移呢?
final int offsetPosition = mAdapterHelper.findPositionOffset(position);
if (offsetPosition < 0 || offsetPosition >=mAdapter.getItemCount()) {
throw newIndexOutOfBoundsException("Inconsistency detected. Invalid item "
+ "position "+ position + "(offset:" + offsetPosition + ")."
+ "state:" +mState.getItemCount());
}
//看名字来说这个方法就是预处理一下?错了,就是在这个方法中发生了绑定
tryBindViewHolderByDeadline(holder, offsetPosition, position,FOREVER_NS);
//向下转型
final ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
final LayoutParams rvLayoutParams;
if (lp == null) {
rvLayoutParams = (LayoutParams)generateDefaultLayoutParams();
holder.itemView.setLayoutParams(rvLayoutParams);
//如果这个参数未被检查(?)过
} else if (!checkLayoutParams(lp)) {
rvLayoutParams = (LayoutParams)generateLayoutParams(lp);
holder.itemView.setLayoutParams(rvLayoutParams);
} else {
rvLayoutParams = (LayoutParams)lp;
}
//一开始我想,布局参数里还能维护这些实例的?神魔恋?一看,果然又是他自定义的布局参数类
//设置成脏item(?)
rvLayoutParams.mInsetsDirty = true;
//把holder交给他去维护
rvLayoutParams.mViewHolder = holder;
//等待校验中
rvLayoutParams.mPendingInvalidate = holder.itemView.getParent() == null;
}
//转换预布局成布局后
//rv提供人工的位置范围在prelayout状态(终于领悟到了是还未布局的状态),并且自动的把这些位置映射到Adapter的位置当getViewForPosition(int)方法或者bindViewToPosition(View, int)被调用。通常,LayoutManager不需要去忧虑这个问题。然而,在某些情况下,你的LayoutManager或许需要去调用一些自定义组件,其中包含项目位置,在这种情况下你需要实际的Adapter的位置而不是prelayout的位置。你可以使用这个方法去转换一个prelayout的位置成Adapter的位置。注意如果被分享的位置属于一个被删除的ViewHolder,这个方法将会返回-1。调用这个方法在布局后状态将返回相同的值。
public intconvertPreLayoutPositionToPostLayout(int position) {
if (position < 0 || position >= mState.getItemCount()) {
throw newIndexOutOfBoundsException("invalid position " + position + ".State "
+ "item count is" + mState.getItemCount());
}
if (!mState.isPreLayout()) {
return position;
}
return mAdapterHelper.findPositionOffset(position);
}
//获得为给定位置初始化的视图。这个方法应该被LayoutManager的实现类使用,并以此获得views去代表来自Adapter的数据。Recycler可能会重复使用一个报废的或者被脱离联系的View从一个被共享的pool中如果这个是可用的对于正确的view类型。如果适配器没有指出在给定位置的数据已经改变了,这个Recycler将会试图去返回之前为该数据初始化的废料视图,而不是重新绑定。
public View getViewForPosition(intposition) {
return getViewForPosition(position, false);
}
View getViewForPosition(int position,boolean dryRun) {
return tryGetViewHolderForPositionByDeadline(position, dryRun,FOREVER_NS).itemView;
}
//试图从给定的位置去获取ViewHolder,无论是从Recycler的废品,缓存,RecyclerViewPool或者直接的创建
如果在FOREVER_NS之外的截止日期被传递,那么这个方法会尽早返回而不是构建或绑定ViewHolder如果它不认为有这么宽裕的时间。如果必须构造一个ViewHolder并且没有足够的时间,将返回null,如果一个ViewHolder已经被获得&