onAttachedToRecyclerView
notifyItemChange notifyItemRemove
notifyDataChange
ViewHolder
RecyclerViewDataObserver
onBindViewHolder notifyItemRangeChanged
onItemRangeChanged positionStart itemCount ,payload
mIsAttached
AdapterHelper
triggerUpdateProcessor requestLayout
setAdapter
setAdapterInternal
adapter.onAttachedToRecyclerView(this);RecyclerView
mTestAdapter.notifyItemChanged(3);
RecyclerView
public final void notifyItemChanged(int position) {
mObservable.notifyItemRangeChanged(position, 1);
}
notifyItemRangeChanged(positionStart, itemCount, null);
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onItemRangeChanged(positionStart, itemCount, payload);
}
public static abstract class AdapterDataObserver {
public void onChanged() {
// Do nothing
}
public void onItemRangeChanged(int positionStart, int itemCount) {
// do nothing
}
public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
// fallback to onItemRangeChanged(positionStart, itemCount) if app
// does not override this method.
onItemRangeChanged(positionStart, itemCount);
}
public void onItemRangeInserted(int positionStart, int itemCount) {
// do nothing
}
public void onItemRangeRemoved(int positionStart, int itemCount) {
// do nothing
}
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
// do nothing
}
}
AdapterDataObserver RecyclerViewDataObserver
RecyclerView
private final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver();
private class RecyclerViewDataObserver extends AdapterDataObserver {
onItemRangeChanged triggerUpdateProcessor requestLayout
boolean onItemRangeChanged(int positionStart, int itemCount, Object payload) {
mPendingUpdates.add(obtainUpdateOp(UpdateOp.UPDATE, positionStart, itemCount, payload));
mExistingUpdateTypes |= UpdateOp.UPDATE;
return mPendingUpdates.size() == 1;
}
size == 1时才 requestLayout,第一次时 onItemRangeChanged时才 requestLayout
final ArrayList<UpdateOp> mPendingUpdates = new ArrayList<UpdateOp>();
notifyItemChange ViewHolder 动画效果xiao
局部刷新
oldHolder newHolder
scrapView
// 如果不需要更新 放到 mAttachedScrap 中
if (holder.hasAnyOfTheFlags(ViewHolder.FLAG_REMOVED | ViewHolder.FLAG_INVALID)
// 没有更新 或者 可以被复用
|| !holder.isUpdated() || canReuseUpdatedViewHolder(holder)) {
...
holder.setScrapContainer(this, false);
mAttachedScrap.add(holder);
} else {
// 需要更新 放到 mChangedScrap 中
if (mChangedScrap == null) {
mChangedScrap = new ArrayList<ViewHolder>();
}
holder.setScrapContainer(this, true);
mChangedScrap.add(holder);
canReuseUpdatedViewHolder
void scrapView(View view) {
final ViewHolder holder = getChildViewHolderInt(view);
holder.setScrapContainer(this);
if (!holder.isChanged() || !supportsChangeAnimations()) {
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.");
}
mAttachedScrap.add(holder);
} else {
if (mChangedScrap == null) {
mChangedScrap = new ArrayList<ViewHolder>();
}
mChangedScrap.add(holder);
}
}
notifyItemChange requestLayout bindViewHolder
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
dispatchLayout();
mFirstLayoutComplete = true;
}
//2.mInPreLayout 设置为 true 后面有用
mState.mInPreLayout = mState.mRunPredictiveAnimations;
//5.保存动画信息相关
mViewInfoStore.addToPreLayout(holder, animationInfo);
//3.如果holder确定要更新,就把它添加到 oldChangeHolders 集合中
long key = getChangedHolderKey(holder);
mViewInfoStore.addToOldChangeHolders(key, holder);
@VisibleForTesting
final LongSparseArray<RecyclerView.ViewHolder> mOldChangedHolders = new LongSparseArray<>();
public void onLayoutChildren(Recycler recycler, State state) {
Log.e(TAG, "You must override onLayoutChildren(Recycler recycler, State state) ");
}
private void processAdapterUpdatesAndSetAnimationFlags() {
// 通常情况就是 ture
mState.mRunSimpleAnimations = true
// 通常情况就是 ture
mState.mRunPredictiveAnimations = true
mAdapterHelper.preProcess();
for (int i = 0; i < count; i++) {
UpdateOp op = mPendingUpdates.get(i);
case UpdateOp.UPDATE:
applyUpdate(op);
break;
UpdateOp newOp = obtainUpdateOp(UpdateOp.UPDATE, tmpStart, tmpCount,
op.payload);
postponeAndUpdateViewHolders(newOp);
case UpdateOp.UPDATE:
mCallback.markViewHoldersUpdated(op.positionStart, op.itemCount, op.payload);
break;
void initAdapterManager() {
mAdapterHelper = new AdapterHelper(new AdapterHelper.Callback() {
@Override
public void markViewHoldersUpdated(int positionStart, int itemCount, Object payload) {
viewRangeUpdate(positionStart, itemCount, payload);
mItemsChanged = true;
}
void viewRangeUpdate(int positionStart, int itemCount, Object payload) {
final int childCount = mChildHelper.getUnfilteredChildCount();
final int positionEnd = positionStart + itemCount;
if (holder.mPosition >= positionStart && holder.mPosition < positionEnd) {
// We re-bind these view holders after pre-processing is complete so that
// ViewHolders have their final positions assigned.
holder.addFlags(ViewHolder.FLAG_UPDATE);
holder.addChangePayload(payload);
// lp cannot be null since we get ViewHolder from it.
((LayoutParams) child.getLayoutParams()).mInsetsDirty = true;
}
processAdapterUpdatesAndSetAnimationFlags();
if (mState.mTrackOldChangeHolders && holder.isUpdated() && !holder.isRemoved()
&& !holder.shouldIgnore() && !holder.isInvalid()) {
long key = getChangedHolderKey(holder);
// This is NOT the only place where a ViewHolder is added to old change holders
// list. There is another case where:
// * A VH is currently hidden but not deleted
// * The hidden item is changed in the adapter
// * Layout manager decides to layout the item in the pre-Layout pass (step1)
// When this case is detected, RV will un-hide that view and add to the old
// change holders list.
mViewInfoStore.addToOldChangeHolders(key, holder);
}
@VisibleForTesting
final LongSparseArray<RecyclerView.ViewHolder> mOldChangedHolders = new LongSparseArray<>();
//4.很重要,LayoutManager 开始工作
mLayout.onLayoutChildren(mRecycler, mState);
for (int i = childCount - 1; i >= 0; i--) {
final View v = getChildAt(i);
scrapOrRecycleView(recycler, i, v);
}
return ((LayoutParams) child.getLayoutParams()).mViewHolder;
recycler.scrapView(view);
不更新
mAttachedScrap.add(holder);
public final class Recycler {
final ArrayList<ViewHolder> mAttachedScrap = new ArrayList<>();
更新的话
mChangedScrap.add(holder);
ArrayList<ViewHolder> mChangedScrap = null;
ViewHolder tryGetViewHolderForPositionByDeadline(int position,
boolean dryRun, long deadlineNs) {
if (mState.isPreLayout()) {
holder = getChangedScrapViewForPosition(position);
final ViewHolder holder = mChangedScrap.get(i);
holder = getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);
final ViewHolder holder = mAttachedScrap.get(i);
Recycler
final ViewHolder holder = mCachedViews.get(i);
final ArrayList<ViewHolder> mCachedViews = new ArrayList<ViewHolder>();
final int offsetPosition = mAdapterHelper.findPositionOffset(position);
...
final int type = mAdapter.getItemViewType(offsetPosition);
final View view = mViewCacheExtension
.getViewForPositionAndType(this, position, type);
//4. 从 RecycledViewPool 中查找
holder = getRecycledViewPool().getRecycledView(type);
...
//5. 老实创建
holder = mAdapter.createViewHolder(RecyclerView.this, type);
...
dispatchLayoutStep2
// Step 2: Run layout
mState.mInPreLayout = false;
mLayout.onLayoutChildren(mRecycler, mState);
ActiveViews和mAttachedScrap功能相似
mScrapVIew和mCachedViews + mRecyclerPool|否|是|与自身生命周期一致
makeAndAddView
mActiveViews|否|否|onLayout函数周期内|用于屏幕内itemView快速重用|
listview
makeAndAddView
mScrapVIew和mCachedViews
mAdapter .getView
createView , view
RecyclerView
getViewForPosition
mAttachedScrap|否|否|onLayout函数周期内|用于屏幕内itemView快速重用|
mCacheViews的使用
mViewCacheExtension||||不直接使用
mRecyclerPool|否|是|与自身生命周期一致
mAdapter.createViewHolder
mAdapter.binderViewHolder
public void setAdapter(ListAdapter adapter) {
if (mAdapter != null) {
mAdapter.unregisterDataSetObserver(mObserver);
}
if (adapter != null) {
adapter.registerDataSetObserver(mObserver);
mRecycler.setViewTypeCount(adapter.getViewTypeCount());
mHasStableIds = adapter.hasStableIds();
} else {
mHasStableIds = false;
}
populate();
layoutChildren(mDataChanged);
View newView = obtainView(position, child);
view = mAdapter.getView(position, scrap, this);
if (view != scrap && scrap != null) {
// The adapter didn't use it; put it back.
mRecycler.addScrap(scrap);
}
View getView(int position, View convertView, ViewGroup parent);
private class RecycleBin {
private ArrayList<View>[] mScrapViews;
ArrayList<View>[] scrapViews = new ArrayList[viewTypeCount];
for (int i = 0; i < viewTypeCount; i++) {
scrapViews[i] = new ArrayList<View>();
}
onLayout
@Override
protected void layoutChildren() {
// Flush any cached views that did not get reused above
recycleBin.scrapActiveViews();
if (hasListener) {
mRecyclerListener.onMovedToScrapHeap(victim);
}
layoutChildren
RecycleBin
addScrapView changed
fillActiveViews no changed
// Clear out old views
detachAllViewsFromParent();
makeAndAddView
if (params.viewType == mAdapter.getItemViewType(position)) {
final View updatedView = mAdapter.getView(position, transientView, this);
mAdapter.getView
detachViewFromParent
layoutChildren fillFromTop
fillDown
makeAndAddView
setupChild
attachViewToParent
getItemViewType getViewTypeCount
addViewAbove addViewBelow
mActiveViews 一级缓存
mScrapViews 二级缓存
mActiveViews ,mAtta
Recycler
scrapList mAttachedScrap mChangedScrap mCacheViews RecycledViewPool
tryGetViewHolderForPositionByDeadline
onBindViewHolder
detachAndScrapAttachedViews
vh.addFlags(ViewHolder.FLAG_TMP_DETACHED);
FLAG_TMP_DETACHED
recycleByLayoutState(recycler, layoutState); //根据滚动的距离来回收Viewvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
void recycleViewHolderInternal(ViewHolder holder) {
void recycleViewHolderInternal(ViewHolder holder) {
void recycleCachedViewAt(int cachedViewIndex) {
if (DEBUG) {
Log.d(TAG, "Recycling cached view at index " + cachedViewIndex);
}
ViewHolder viewHolder = mCachedViews.get(cachedViewIndex);
if (DEBUG) {
Log.d(TAG, "CachedViewHolder to be recycled: " + viewHolder);
}
addViewHolderToRecycledViewPool(viewHolder, true);
mCachedViews.remove(cachedViewIndex);
}
mCacheViews recycleCachedViewAt
addViewHolderToRecycledViewPool(viewHolder, true);
mCachedViews.remove(cachedViewIndex);
getRecycledViewPool().putRecycledView(holder);
RecycledViewPool
mCachedViews.add(targetCacheIndex, holder);
createViewHolder
bindViewHolder
child.getLayoutParams
child.getLeft params.leftMargin
RecycleView.LayoutManager
StaggeredGridLayoutManager 瀑布就式布局管理器
getItemOffsets
onBindViewHolder
holder.sg_item.getLayoutParams
layoutParams.height = heights.get position
ItemTouchHelper attachToRecyclerView