想研究清楚RecyclerView#Adapter#notifyDataSetChanged
是如何更新數據的,我們需要從RecyclerView#setAdapter()
方法看起。
RecyclerView#setAdapter()方法:
主要是調用了RecyclerView#setAdapterInternal
方法,然后調用requestLayout
進行布局更新。
public void setAdapter(@Nullable Adapter adapter) {
// bail out if layout is frozen
setLayoutFrozen(false);
setAdapterInternal(adapter, false, true);
processDataSetCompletelyChanged(false);
requestLayout();
}
RecyclerView#setAdapterInternal
方法:將原有的Adapter
替換為新的Adapter
,同時觸發對應的Listeners。
①給原來的Adapter
解除與RecyclerView#mObserver
的綁定。mObserver
是RecyclerViewDataObserver
的實例。
②調用removeAndRecycleViews
方法。清除mAttachedScrap
。
③將新的Adapter與RecyclerView#mObserver
進行綁定。
④通知LayoutManager
和RecyclerView
相應的數據變更。
private void setAdapterInternal(@Nullable Adapter adapter, boolean compatibleWithPrevious,
boolean removeAndRecycleViews) {
// 給原來的Adapter解除與RecyclerView#mObserver的綁定。mObserver是RecyclerViewDataObserver的實例。
if (mAdapter != null) {
mAdapter.unregisterAdapterDataObserver(mObserver);
mAdapter.onDetachedFromRecyclerView(this);
}
if (!compatibleWithPrevious || removeAndRecycleViews) {
// 清空mAttachedScrap和mChangedScrap;將mCachedViews中的ViewHolder添加到RecycledViewPool中;清空mCachedViews。
removeAndRecycleViews();
}
mAdapterHelper.reset();
final Adapter oldAdapter = mAdapter;
mAdapter = adapter;
if (adapter != null) {
// 將新的Adapter與RecyclerView#mObserver進行綁定。
adapter.registerAdapterDataObserver(mObserver);
adapter.onAttachedToRecyclerView(this);
}
// 通知Layout和RecyclerView數據變更。
if (mLayout != null) {
mLayout.onAdapterChanged(oldAdapter, mAdapter);
}
mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious);
mState.mStructureChanged = true;
}
接下來看一下我們的重點,Adapter
是如何與RecyclerView
關聯起來的。
RecyclerView#Adapter#registerAdapterDataObserver(mObserver):
首先,mObserver
是RecyclerViewDataObserver
,是RecyclerView
的成員變量。
public class RecyclerView extends ViewGroup implements ScrollingView,
NestedScrollingChild2, NestedScrollingChild3 {
private final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver();
}
接著看RecyclerView#Adapter#registerAdapterDataObserver
方法:
public abstract static class Adapter<VH extends ViewHolder> {
private final AdapterDataObservable mObservable = new AdapterDataObservable();
public void registerAdapterDataObserver(@NonNull AdapterDataObserver observer) {
mObservable.registerObserver(observer);
}
}
AdapterDataObservable
是典型的觀察者模式
,它是被觀察者(數據發生變動的一方)
,繼承了Observable
接口:
static class AdapterDataObservable extends Observable<AdapterDataObserver> {
...
}
Observable#registerObserver
方法:將觀察者對象添加進列表
。
public abstract class Observable<T> {
protected final ArrayList<T> mObservers = new ArrayList<T>();
public void registerObserver(T observer) {
if (observer == null) {
throw new IllegalArgumentException("The observer is null.");
}
synchronized(mObservers) {
if (mObservers.contains(observer)) {
throw new IllegalStateException("Observer " + observer + " is already registered.");
}
mObservers.add(observer);
}
}
...
}
總結一下,RecyclerView#Adapter#registerAdapterDataObserver
方法,會將RecyclerView
中的RecyclerViewDataObserver
對象mObserver
當做觀察者,添加到RecyclerView#Adapter
中的AdapterDataObservable
對象mObservable
中,這樣Adapter
就可以作為被觀察者,通知RecyclerView
(觀察者)數據變動了。
RecyclerView#Adapter#notifyDataSetChanged方法
接著來看下RecyclerView#Adapter#notifyDataSetChanged
方法是如何更新數據的。
public final void notifyDataSetChanged() {
mObservable.notifyChanged();
}
這樣就調用到了RecyclerView#AdapterDataObservable#notifyChanged
方法:
static class AdapterDataObservable extends Observable<AdapterDataObserver> {
public void notifyChanged() {
// 通知每個注冊的觀察者,數據有變動。
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
由于我們已經將RecyclerView#RecyclerViewDataObserver
當做觀察者注冊給AdapterDataObservable
了,所以會調用到RecyclerView#RecyclerViewDataObserver#onChanged
方法:
private class RecyclerViewDataObserver extends AdapterDataObserver {
@Override
public void onChanged() {
...
// 清空mCachedViews
processDataSetCompletelyChanged(true);
// 調用requestLayout,刷新UI
if (!mAdapterHelper.hasPendingUpdates()) {
requestLayout();
}
}
}
所以會調用到RecyclerView#processDataSetCompletelyChanged
方法:給 mChildHelper
中和 mCachedViews
的ViewHolder
添加 FLAG_UPDATE
和 FLAG_INVALID
標記。并將mCachedViews
中的ViewHolder
添加到到RecycledViewPool
中;清空mCachedViews
。
void processDataSetCompletelyChanged(boolean dispatchItemsChanged) {
mDispatchItemsChangedEvent |= dispatchItemsChanged;
mDataSetHasChangedAfterLayout = true;
// 給 mChildHelper 中和 mCachedViews 的ViewHolder添加 FLAG_UPDATE 和 FLAG_INVALID 標記。并將mCachedViews中的ViewHolder添加到到RecycledViewPool中;清空mCachedViews
markKnownViewsInvalid();
}
RecyclerView#markKnownViewsInvalid
方法:
①給mChildHelper
中的ViewHolder
添加 FLAG_UPDATE
和 FLAG_INVALID
標記
②給mCachedViews
中的ViewHolder
添加 FLAG_UPDATE
和 FLAG_INVALID
標記,并將ViewHolder
添加到到RecycledViewPool
中;清空mCachedViews
void markKnownViewsInvalid() {
// 給mChildHelper中的ViewHolder添加 FLAG_UPDATE 和 FLAG_INVALID 標記
final int childCount = mChildHelper.getUnfilteredChildCount();
for (int i = 0; i < childCount; i++) {
final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i));
if (holder != null && !holder.shouldIgnore()) {
holder.addFlags(ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID);
}
}
...
// 給mCachedViews中的ViewHolder添加 FLAG_UPDATE 和 FLAG_INVALID 標記,并將ViewHolder添加到到RecycledViewPool中;清空mCachedViews
mRecycler.markKnownViewsInvalid();
}
RecyclerView#Recycler#markKnownViewsInvalid
方法:
①給 mCachedViews
中的ViewHolder
添加 FLAG_UPDATE
和 FLAG_INVALID
標記
②將mCachedViews
中的ViewHolder
添加到RecycledViewPool
中;清空mCachedViews
void markKnownViewsInvalid() {
// 給 mCachedViews 中的ViewHolder添加 FLAG_UPDATE 和 FLAG_INVALID 標記
final int cachedCount = mCachedViews.size();
for (int i = 0; i < cachedCount; i++) {
final ViewHolder holder = mCachedViews.get(i);
if (holder != null) {
holder.addFlags(ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID);
holder.addChangePayload(null);
}
}
// 將mCachedViews中的ViewHolder添加到RecycledViewPool中;清空mCachedViews
if (mAdapter == null || !mAdapter.hasStableIds()) {
// we cannot re-use cached views in this case. Recycle them all
recycleAndClearCachedViews();
}
}
總結
1、調用RecyclerView#setAdapter()方法后:將原有的Adapter
替換為新的Adapter
,同時觸發對應的Listeners。
①給原來的Adapter
解除與RecyclerView#mObserver
的綁定。mObserver
是RecyclerViewDataObserver
的實例。
②調用removeAndRecycleViews
方法。清除mAttachedScrap
。
③將新的Adapter與RecyclerView#mObserver
進行綁定。
④通知LayoutManager
和RecyclerView
相應的數據變更。
2、RecyclerView#Adapter#notifyDataSetChanged
方法調用后,通知RecyclerView
數據變化,主要做了以下工作:
①通過觀察者模式
,由被觀察者Adapter
通知觀察者RecyclerView
進行對應的變更。
②RecyclerView
中,給 mChildHelper
中和 mCachedViews
的ViewHolder
添加 FLAG_UPDATE
和 FLAG_INVALID
標記。并將mCachedViews
中的ViewHolder
添加到到RecycledViewPool
中;清空mCachedViews
。
③調用requestLayout
刷新UI。