RecyclerView學(xué)習(xí)-RecyclerView#Adapter#notifyDataSetChanged是如何更新數(shù)據(jù)的?

想研究清楚RecyclerView#Adapter#notifyDataSetChanged是如何更新數(shù)據(jù)的,我們需要從RecyclerView#setAdapter()方法看起。

RecyclerView#setAdapter()方法:

主要是調(diào)用了RecyclerView#setAdapterInternal方法,然后調(diào)用requestLayout進(jìn)行布局更新。

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,同時(shí)觸發(fā)對(duì)應(yīng)的Listeners。
①給原來(lái)的Adapter解除與RecyclerView#mObserver的綁定。mObserverRecyclerViewDataObserver的實(shí)例。
②調(diào)用removeAndRecycleViews方法。清除mAttachedScrap。
③將新的Adapter與RecyclerView#mObserver進(jìn)行綁定。
④通知LayoutManagerRecyclerView相應(yīng)的數(shù)據(jù)變更。

private void setAdapterInternal(@Nullable Adapter adapter, boolean compatibleWithPrevious,
        boolean removeAndRecycleViews) {
    // 給原來(lái)的Adapter解除與RecyclerView#mObserver的綁定。mObserver是RecyclerViewDataObserver的實(shí)例。
    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進(jìn)行綁定。
        adapter.registerAdapterDataObserver(mObserver);
        adapter.onAttachedToRecyclerView(this);
    }
    // 通知Layout和RecyclerView數(shù)據(jù)變更。
    if (mLayout != null) {
        mLayout.onAdapterChanged(oldAdapter, mAdapter);
    }
    mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious);
    mState.mStructureChanged = true;
}

接下來(lái)看一下我們的重點(diǎn),Adapter是如何與RecyclerView關(guān)聯(lián)起來(lái)的。

RecyclerView#Adapter#registerAdapterDataObserver(mObserver):

首先,mObserverRecyclerViewDataObserver,是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是典型的觀察者模式,它是被觀察者(數(shù)據(jù)發(fā)生變動(dòng)的一方),繼承了Observable接口:

static class AdapterDataObservable extends Observable<AdapterDataObserver> {
    ...
}

Observable#registerObserver方法:將觀察者對(duì)象添加進(jìn)列表。

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);
        }
    }
    ...
}

總結(jié)一下,RecyclerView#Adapter#registerAdapterDataObserver方法,會(huì)將RecyclerView中的RecyclerViewDataObserver對(duì)象mObserver當(dāng)做觀察者,添加到RecyclerView#Adapter中的AdapterDataObservable對(duì)象mObservable中,這樣Adapter就可以作為被觀察者,通知RecyclerView(觀察者)數(shù)據(jù)變動(dòng)了。

RecyclerView#Adapter#notifyDataSetChanged方法

接著來(lái)看下RecyclerView#Adapter#notifyDataSetChanged方法是如何更新數(shù)據(jù)的。

public final void notifyDataSetChanged() {
    mObservable.notifyChanged();
}

這樣就調(diào)用到了RecyclerView#AdapterDataObservable#notifyChanged方法:

static class AdapterDataObservable extends Observable<AdapterDataObserver> {
    public void notifyChanged() {
        // 通知每個(gè)注冊(cè)的觀察者,數(shù)據(jù)有變動(dòng)。
        for (int i = mObservers.size() - 1; i >= 0; i--) {
            mObservers.get(i).onChanged();
        }
    }
}

由于我們已經(jīng)將RecyclerView#RecyclerViewDataObserver當(dāng)做觀察者注冊(cè)給AdapterDataObservable了,所以會(huì)調(diào)用到RecyclerView#RecyclerViewDataObserver#onChanged方法:

private class RecyclerViewDataObserver extends AdapterDataObserver {
   
    @Override
    public void onChanged() {
        ...
        // 清空mCachedViews
        processDataSetCompletelyChanged(true);
        // 調(diào)用requestLayout,刷新UI
        if (!mAdapterHelper.hasPendingUpdates()) {
            requestLayout();
        }
    }
}

所以會(huì)調(diào)用到RecyclerView#processDataSetCompletelyChanged方法:給 mChildHelper 中和 mCachedViewsViewHolder添加 FLAG_UPDATEFLAG_INVALID 標(biāo)記。并將mCachedViews中的ViewHolder添加到到RecycledViewPool中;清空mCachedViews

void processDataSetCompletelyChanged(boolean dispatchItemsChanged) {
    mDispatchItemsChangedEvent |= dispatchItemsChanged;
    mDataSetHasChangedAfterLayout = true;
    // 給 mChildHelper 中和 mCachedViews 的ViewHolder添加 FLAG_UPDATE 和 FLAG_INVALID 標(biāo)記。并將mCachedViews中的ViewHolder添加到到RecycledViewPool中;清空mCachedViews
    markKnownViewsInvalid();
}

RecyclerView#markKnownViewsInvalid方法:
①給mChildHelper中的ViewHolder添加 FLAG_UPDATEFLAG_INVALID 標(biāo)記
②給mCachedViews中的ViewHolder添加 FLAG_UPDATEFLAG_INVALID 標(biāo)記,并將ViewHolder添加到到RecycledViewPool中;清空mCachedViews

void markKnownViewsInvalid() {
    // 給mChildHelper中的ViewHolder添加 FLAG_UPDATE 和 FLAG_INVALID 標(biāo)記
    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 標(biāo)記,并將ViewHolder添加到到RecycledViewPool中;清空mCachedViews
    mRecycler.markKnownViewsInvalid();
}

RecyclerView#Recycler#markKnownViewsInvalid方法:
①給 mCachedViews 中的ViewHolder添加 FLAG_UPDATEFLAG_INVALID 標(biāo)記
②將mCachedViews中的ViewHolder添加到RecycledViewPool中;清空mCachedViews

void markKnownViewsInvalid() {
    // 給 mCachedViews 中的ViewHolder添加 FLAG_UPDATE 和 FLAG_INVALID 標(biāo)記
    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();
    }
}

總結(jié)

1、調(diào)用RecyclerView#setAdapter()方法后:將原有的Adapter替換為新的Adapter,同時(shí)觸發(fā)對(duì)應(yīng)的Listeners。
①給原來(lái)的Adapter解除與RecyclerView#mObserver的綁定。mObserverRecyclerViewDataObserver的實(shí)例。
②調(diào)用removeAndRecycleViews方法。清除mAttachedScrap。
③將新的Adapter與RecyclerView#mObserver進(jìn)行綁定。
④通知LayoutManagerRecyclerView相應(yīng)的數(shù)據(jù)變更。

2、RecyclerView#Adapter#notifyDataSetChanged方法調(diào)用后,通知RecyclerView數(shù)據(jù)變化,主要做了以下工作:
①通過(guò)觀察者模式,由被觀察者Adapter通知觀察者RecyclerView進(jìn)行對(duì)應(yīng)的變更。
RecyclerView中,給 mChildHelper 中和 mCachedViewsViewHolder添加 FLAG_UPDATEFLAG_INVALID 標(biāo)記。并將mCachedViews中的ViewHolder添加到到RecycledViewPool中;清空mCachedViews
③調(diào)用requestLayout刷新UI。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容