Recyclerview.java
public void setAdapter(@Nullable Adapter adapter) {
// bail out if layout is frozen
// 如果布局被冻结的话,重新激活布局
setLayoutFrozen(false);
//真正设置适配器的方法.
setAdapterInternal(adapter, false, true);
//设置数据集将要完全改变
processDataSetCompletelyChanged(false);
//请求重新布局
requestLayout();
}
setAdapter主要是调用了setLayoutFrozen方法和setAdapterInternal方法.接下来就分析这两个方法.
Recyclerview.java
public void setLayoutFrozen(boolean frozen) {
//mLayoutFrozen默认就是false,用来控制是否冻结布局的.当设置为true时,就会冻结布局和滑动
if (frozen != mLayoutFrozen) {
//如果recycleview正在layout或者scroll就抛出异常
assertNotInLayoutOrScroll("Do not setLayoutFrozen in layout or scroll");
if (!frozen) {
//frozen为false,表示要重新激活布局,所以将mLayoutFrozen设置为false
mLayoutFrozen = false;
if (mLayoutRequestEaten && mLayout != null && mAdapter != null) {
//请求重新布局
requestLayout();
}
mLayoutRequestEaten = false;
} else {
final long now = SystemClock.uptimeMillis();
//获取ACTION_CANCEL事件
MotionEvent cancelEvent = MotionEvent.obtain(now, now,
MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
//执行ACTION_CANCEL的逻辑,取消滑动相关的配置
onTouchEvent(cancelEvent);
//同时将mLayoutFrozen 设置为true,冻结布局和滑动
mLayoutFrozen = true;
mIgnoreMotionEventTillDown = true;
//停止一切滑动
stopScroll();
}
}
}
setLayoutFrozen方法主要是在设置真正的适配器之前确保布局是激活的.下面在看看setAdapterInternal方法.
Recyclerview.java
private void setAdapterInternal(Adapter adapter, boolean compatibleWithPrevious,
boolean removeAndRecycleViews) {
if (mAdapter != null) {
// mAdapter表示原来的适配器,如果不为null,就取消注册的观察者和recycleview的关联.
mAdapter.unregisterAdapterDataObserver(mObserver);
mAdapter.onDetachedFromRecyclerView(this);
}
if (!compatibleWithPrevious || removeAndRecycleViews) {
// 停止所有的动画
if (mItemAnimator != null) {
mItemAnimator.endAnimations();
}
//mLayout就是layoutmanager布局管理器,用来管理布局和滑动的,mRecycler就是Recycle用来管理item的复用的.这里就是清除掉之前的item.
if (mLayout != null) {
mLayout.removeAndRecycleAllViews(mRecycler);
mLayout.removeAndRecycleScrapInt(mRecycler);
}
mRecycler.clear();
}
mAdapterHelper.reset();
//用oldAdapter记录之前的适配器,将新的适配器赋值给mAdapter
final Adapter oldAdapter = mAdapter;
mAdapter = adapter;
//给适配器注册观察者并且和recycleview关联起来
if (adapter != null) {
adapter.registerAdapterDataObserver(mObserver);
adapter.onAttachedToRecyclerView(this);
}
//将2个适配器传给mLayout
if (mLayout != null) {
mLayout.onAdapterChanged(oldAdapter, mAdapter);
}
mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious);
mState.mStructureChanged = true;
markKnownViewsInvalid();
}
通过分析setAdapterInternal的源码,我们知道该方法的主要动作是,移除LayoutManager中的视图、清空Recycler mRecycler中的数据、更新Adapter mAdapter域、注册数据观察者、Adapter和RecyclerView绑定;
接下来,我们主要关心setAdapter之后是如何重新绑定数据,刷新View,即调用
onBindViewHolder(@NonNull VH holder, int position, @NonNull List<Object> payloads) 方法的过程
Recyclerview.java
@Override
public void requestLayout() {
//setAdapter的时候设置了mLayoutFrozen为false,所以会调用super.requestLayout();
if (mInterceptRequestLayoutDepth == 0 && !mLayoutFrozen) {
super.requestLayout();
} else {
mLayoutWasDefered = true;
}
}
最终会调用measure、layout、draw方法来进行View的三大工作流程
Recyclerview.java
protected void onMeasure(int widthSpec, int heightSpec) {
if (mLayout == null) {
defaultOnMeasure(widthSpec, heightSpec);
return;
}
if (mLayout.isAutoMeasureEnabled()) {
final int widthMode = MeasureSpec.getMode(widthSpec);
final int heightMode = MeasureSpec.getMode(heightSpec);
/**
* This specific call should be considered deprecated and replaced with
* {@link #defaultOnMeasure(int, int)}. It can't actually be replaced as it could
* break existing third party code but all documentation directs developers to not
* override {@link LayoutManager#onMeasure(int, int)} when
* {@link LayoutManager#isAutoMeasureEnabled()} returns true.
*/
mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec);
final boolean measureSpecModeIsExactly =
widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY;
if (measureSpecModeIsExactly || mAdapter == null) {
return;
}
if (mState.mLayoutStep == State.STEP_START) {
dispatchLayoutStep1();
}
// set dimensions in 2nd step. Pre-layout should happen with old dimensions for
// consistency
mLayout.setMeasureSpecs(widthSpec, heightSpec);
mState.mIsMeasuring = true;
//进行实际布局
dispatchLayoutStep2();
// now we can get the width and height from the children.
mLayout.setMeasuredDimensionFromChildren(widthSpec, heightSpec);
// if RecyclerView has non-exact width and height and if there is at least one child
// which also has non-exact width & height, we have to re-measure.
if (mLayout.shouldMeasureTwice()) {
mLayout.setMeasureSpecs(
MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
mState.mIsMeasuring = true;
//进行实际布局
dispatchLayoutStep2();
// now we can get the width and height from the children.
mLayout.setMeasuredDimensionFromChildren(widthSpec, heightSpec);
}
} else {
if (mHasFixedSize) {
mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec);
return;
}
.....
}
onMeasure中会调用dispatchLayoutStep2()方法,进行实际布局。
Recyclerview.java
private void dispatchLayoutStep2() {
startInterceptRequestLayout();
onEnterLayoutOrScroll();
mState.assertLayoutStep(State.STEP_LAYOUT | State.STEP_ANIMATIONS);
mAdapterHelper.consumeUpdatesInOnePass();
mState.mItemCount = mAdapter.getItemCount();
mState.mDeletedInvisibleItemCountSincePreviousLayout = 0;
// Step 2: Run layout
mState.mInPreLayout = false;
//布局管理器 布局给定适配器中的所有相关子视图。
mLayout.onLayoutChildren(mRecycler, mState);
mState.mStructureChanged = false;
mPendingSavedState = null;
// onLayoutChildren may have caused client code to disable item animations; re-check
mState.mRunSimpleAnimations = mState.mRunSimpleAnimations && mItemAnimator != null;
mState.mLayoutStep = State.STEP_ANIMATIONS;
onExitLayoutOrScroll();
stopInterceptRequestLayout(false);
}
dispatchLayoutStep2()方法中调用mLayout.onLayoutChildren(mRecycler, mState);即使用布局管理器 布局给定适配器中的所有相关子视图。这里以LinearLayoutManager为视角查看实现
LinearLayoutManager.java
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
........
if (mAnchorInfo.mLayoutFromEnd) {
// fill towards start
updateLayoutStateToFillStart(mAnchorInfo);
mLayoutState.mExtra = extraForStart;
//填充由mLayoutState定义的给定布局
fill(recycler, mLayoutState, state, false);
startOffset = mLayoutState.mOffset;
final int firstElement = mLayoutState.mCurrentPosition;
if (mLayoutState.mAvailable > 0) {
extraForEnd += mLayoutState.mAvailable;
}
// fill towards end
updateLayoutStateToFillEnd(mAnchorInfo);
mLayoutState.mExtra = extraForEnd;
mLayoutState.mCurrentPosition += mLayoutState.mItemDirection;
fill(recycler, mLayoutState, state, false);
endOffset = mLayoutState.mOffset;
if (mLayoutState.mAvailable > 0) {
// end could not consume all. add more items towards start
extraForStart = mLayoutState.mAvailable;
updateLayoutStateToFillStart(firstElement, startOffset);
mLayoutState.mExtra = extraForStart;
fill(recycler, mLayoutState, state, false);
startOffset = mLayoutState.mOffset;
}
} else {
// fill towards end
updateLayoutStateToFillEnd(mAnchorInfo);
mLayoutState.mExtra = extraForEnd;
//填充由mLayoutState定义的给定布局
fill(recycler, mLayoutState, state, false);
endOffset = mLayoutState.mOffset;
final int lastElement = mLayoutState.mCurrentPosition;
if (mLayoutState.mAvailable > 0) {
extraForStart += mLayoutState.mAvailable;
}
// fill towards start
updateLayoutStateToFillStart(mAnchorInfo);
mLayoutState.mExtra = extraForStart;
mLayoutState.mCurrentPosition += mLayoutState.mItemDirection;
fill(recycler, mLayoutState, state, false);
startOffset = mLayoutState.mOffset;
if (mLayoutState.mAvailable > 0) {
extraForEnd = mLayoutState.mAvailable;
// start could not consume all it should. add more items towards end
updateLayoutStateToFillEnd(lastElement, endOffset);
mLayoutState.mExtra = extraForEnd;
fill(recycler, mLayoutState, state, false);
endOffset = mLayoutState.mOffset;
}
}
.......
}
LinearLayoutManager的onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state)方法,里面调用了
fill(RecyclerView.Recycler recycler, LayoutState layoutState, RecyclerView.State state, boolean stopOnFocusable)
即填充由mLayoutState定义的给定布局
LinearLayoutManager.java
int fill(RecyclerView.Recycler recycler, LayoutState layoutState,
RecyclerView.State state, boolean stopOnFocusable) {
// max offset we should set is mFastScroll + available
final int start = layoutState.mAvailable;
if (layoutState.mScrollingOffset != LayoutState.SCROLLING_OFFSET_NaN) {
// TODO ugly bug fix. should not happen
if (layoutState.mAvailable < 0) {
layoutState.mScrollingOffset += layoutState.mAvailable;
}
recycleByLayoutState(recycler, layoutState);
}
int remainingSpace = layoutState.mAvailable + layoutState.mExtra;
LayoutChunkResult layoutChunkResult = mLayoutChunkResult;
while ((layoutState.mInfinite || remainingSpace > 0) && layoutState.hasMore(state)) {
layoutChunkResult.resetInternal();
if (RecyclerView.VERBOSE_TRACING) {
TraceCompat.beginSection("LLM LayoutChunk");
}
//布局块
layoutChunk(recycler, state, layoutState, layoutChunkResult);
if (RecyclerView.VERBOSE_TRACING) {
TraceCompat.endSection();
}
if (layoutChunkResult.mFinished) {
break;
}
...
}
if (DEBUG) {
validateChildOrder();
}
return start - layoutState.mAvailable;
}
走了layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,LayoutState layoutState, LayoutChunkResult result) 方法
LinearLayoutManager.java
void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,
LayoutState layoutState, LayoutChunkResult result) {
//获取要布局的下一个元素的视图
View view = layoutState.next(recycler);
if (view == null) {
if (DEBUG && layoutState.mScrapList == null) {
throw new RuntimeException("received null view when unexpected");
}
// if we are laying out views in scrap, this may return null which means there is
// no more items to layout.
result.mFinished = true;
return;
}
....
}
layoutChunk方法内部调用了LayoutState的next(RecyclerView.Recycler recycler)方法,获取要布局的下一个元素的视图
LayoutState.java
//获取要布局的下一个元素的视图。还根据{@link #mItemDirection}将当前项索引更新为下一个项。
View next(RecyclerView.Recycler recycler) {
if (mScrapList != null) {
return nextViewFromScrapList();
}
//获取为给定位置初始化的视图。
final View view = recycler.getViewForPosition(mCurrentPosition);
mCurrentPosition += mItemDirection;
return view;
}
LayoutState的next方法内部调用了Recycler的getViewForPosition(int position)方法,用于获取为给定位置初始化的视图。
RecyclerView#Recycler.java
public View getViewForPosition(int position) {
return getViewForPosition(position, false);
}
View getViewForPosition(int position, boolean dryRun) {
//尝试从回收器废料、缓存、RecycledViewPool或直接创建它来获得给定位置的ViewHolder。
return tryGetViewHolderForPositionByDeadline(position, dryRun, FOREVER_NS).itemView;
}
最终调用了 tryGetViewHolderForPositionByDeadline(int position,boolean dryRun, long deadlineNs) 方法,尝试从回收器废料、缓存、RecycledViewPool或直接创建它来获得给定位置的ViewHolder。
RecyclerView#Recycler.java
ViewHolder tryGetViewHolderForPositionByDeadline(int position,
boolean dryRun, long deadlineNs) {
// 1) Find by position from scrap/hidden list/cache
if (holder == null) {
holder = getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);
}
if (holder == null) {
final int offsetPosition = mAdapterHelper.findPositionOffset(position);
final int type = mAdapter.getItemViewType(offsetPosition);
// 2) Find from scrap/cache via stable ids, if exists
if (mAdapter.hasStableIds()) {
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.
final View view = mViewCacheExtension
.getViewForPositionAndType(this, position, type);
if (view != null) {
holder = getChildViewHolder(view);
if (holder == null) {
throw new IllegalArgumentException("getViewForPositionAndType returned"
+ " a view which does not have a ViewHolder");
} else if (holder.shouldIgnore()) {
throw new IllegalArgumentException("getViewForPositionAndType returned"
+ " a view that is ignored. You must call stopIgnoring before"
+ " returning this view.");
}
}
}
if (holder == null) { // fallback to pool
holder = getRecycledViewPool().getRecycledView(type);
}
if (holder == null) {
//当holder==null的时候,创建ViewHolder
holder = mAdapter.createViewHolder(RecyclerView.this, type);
}
}
.....
boolean bound = false;
if (mState.isPreLayout() && holder.isBound()) {
// do not update unless we absolutely have to.
holder.mPreLayoutPosition = position;
} else if (!holder.isBound() || holder.needsUpdate() || holder.isInvalid()) {
if (DEBUG && holder.isRemoved()) {
throw new IllegalStateException("Removed holder should be bound and it should"
+ " come here only in pre-layout. Holder: " + holder);
}
final int offsetPosition = mAdapterHelper.findPositionOffset(position);
//尝试绑定视图,并考虑相关的时间信息。如果deadlineNs != FOREVER_NS,此方法可能绑定失败,并返回false。
bound = tryBindViewHolderByDeadline(holder, offsetPosition, position, deadlineNs);
}
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;
}
rvLayoutParams.mViewHolder = holder;
rvLayoutParams.mPendingInvalidate = fromScrapOrHiddenOrCache && bound;
return holder;
}
内部调用了tryBindViewHolderByDeadline(ViewHolder holder, int offsetPosition,int position, long deadlineNs)方法,
尝试绑定视图,并考虑相关的时间信息。如果deadlineNs != FOREVER_NS,此方法可能绑定失败,并返回false。
RecyclerView#Recycler.java
private boolean tryBindViewHolderByDeadline(ViewHolder holder, int offsetPosition,
int position, long deadlineNs) {
holder.mOwnerRecyclerView = RecyclerView.this;
final int viewType = holder.getItemViewType();
long startBindNs = getNanoTime();
if (deadlineNs != FOREVER_NS
&& !mRecyclerPool.willBindInTime(viewType, startBindNs, deadlineNs)) {
// abort - we have a deadline we can't meet
return false;
}
//绑定ViewHolder
mAdapter.bindViewHolder(holder, offsetPosition);
long endBindNs = getNanoTime();
mRecyclerPool.factorInBindTime(holder.getItemViewType(), endBindNs - startBindNs);
attachAccessibilityDelegate(holder.itemView);
if (mState.isPreLayout()) {
holder.mPreLayoutPosition = position;
}
return true;
}
RecyclerView#Adapter.java
public final void bindViewHolder(VH holder, int position) {
holder.mPosition = position;
if (hasStableIds()) {
holder.mItemId = getItemId(position);
}
holder.setFlags(ViewHolder.FLAG_BOUND,
ViewHolder.FLAG_BOUND | ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID
| ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN);
Trace.beginSection(TRACE_BIND_VIEW_TAG);
//子类重写该方法,以显示指定位置的数据
onBindViewHolder(holder, position, holder.getUnmodifiedPayloads());
holder.clearPayload();
final ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
if (layoutParams instanceof RecyclerView.LayoutParams) {
((LayoutParams) layoutParams).mInsetsDirty = true;
}
Trace.endSection();
}
public void onBindViewHolder(VH holder, int position, List<Object> payloads) {
onBindViewHolder(holder, position);
}
public abstract void onBindViewHolder(VH holder, int position);
最终调用了onBindViewHolder(holder, position, holder.getUnmodifiedPayloads());方法
子类重写该方法,以显示指定位置的数据。