To see how RecyclerView# adapt #notifyDataSetChanged updates data, we need to start with RecyclerView#setAdapter().
RecyclerView# setAdapter () method:
Call the RecyclerView#setAdapterInternal method and then call requestLayout to update the layout.
public void setAdapter(@Nullable Adapter adapter) {
// bail out if layout is frozen
setLayoutFrozen(false);
setAdapterInternal(adapter, false, true);
processDataSetCompletelyChanged(false);
requestLayout();
}
Copy the code
RecyclerView#setAdapterInternal method: replace existing Adapter with new Adapter and trigger corresponding Listeners. RecyclerView#mObserver; MObserver is an instance of RecyclerViewDataObserver. ② Call removeAndRecycleViews method. Remove mAttachedScrap. ③ bind the new Adapter to RecyclerView#mObserver. (4) Notify LayoutManager and RecyclerView of the corresponding data changes.
private void setAdapterInternal(@Nullable Adapter adapter, boolean compatibleWithPrevious, Boolean removeAndRecycleViews) {// Unbind old Adapter recycleView #mObserver. MObserver is an instance of RecyclerViewDataObserver. if (mAdapter ! = null) { mAdapter.unregisterAdapterDataObserver(mObserver); mAdapter.onDetachedFromRecyclerView(this); } if (! CompatibleWithPrevious | | removeAndRecycleViews) {/ / empty mAttachedScrap and mChangedScrap; Add ViewHolder in mCachedViews to RecycledViewPool; Empty mCachedViews. removeAndRecycleViews(); } mAdapterHelper.reset(); final Adapter oldAdapter = mAdapter; mAdapter = adapter; if (adapter ! // bind the new Adapter to RecyclerView#mObserver. adapter.registerAdapterDataObserver(mObserver); adapter.onAttachedToRecyclerView(this); } // Notify Layout and RecyclerView of data changes. if (mLayout ! = null) { mLayout.onAdapterChanged(oldAdapter, mAdapter); } mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious); mState.mStructureChanged = true; }Copy the code
Let’s take a look at our focus, how Adapter relates to RecyclerView.
RecyclerView# Adapter# registerAdapterDataObserver (mObserver) :
Firstly, mObserver is a RecyclerViewDataObserver and a member variable of RecyclerView.
public class RecyclerView extends ViewGroup implements ScrollingView,
NestedScrollingChild2, NestedScrollingChild3 {
private final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver();
}
Copy the code
Then see RecyclerView# Adapter# registerAdapterDataObserver method:
public abstract static class Adapter<VH extends ViewHolder> {
private final AdapterDataObservable mObservable = new AdapterDataObservable();
public void registerAdapterDataObserver(@NonNull AdapterDataObserver observer) {
mObservable.registerObserver(observer);
}
}
Copy the code
AdapterDataObservable is a typical observer pattern. It is the observed (the party whose data changes) and inherits the Observable interface:
static class AdapterDataObservable extends Observable<AdapterDataObserver> {
...
}
Copy the code
Observable#registerObserver method: Adds the observer object to the list.
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); }}... }Copy the code
To summarize, RecyclerView# Adapter# registerAdapterDataObserver method, will the RecyclerViewDataObserver RecyclerView object mObserver as an observer, Added to the mObservable AdapterDataObservable in RecyclerView#Adapter so that the Adapter can act as the observed and notify the RecyclerView of changes.
RecyclerView# Adapter# notifyDataSetChanged method
Now look at how the RecyclerView# adapt #notifyDataSetChanged method updates data.
public final void notifyDataSetChanged() {
mObservable.notifyChanged();
}
Copy the code
RecyclerView#AdapterDataObservable#notifyChanged
static class AdapterDataObservable extends Observable<AdapterDataObserver> { public void notifyChanged() { // Notify each registered observer that the data has changed. for (int i = mObservers.size() - 1; i >= 0; i--) { mObservers.get(i).onChanged(); }}}Copy the code
Since we’ve registered RecyclerView#RecyclerViewDataObserver as an observer to the AdapterDataObservable, So it calls RecyclerView#RecyclerViewDataObserver#onChanged:
private class RecyclerViewDataObserver extends AdapterDataObserver { @Override public void onChanged() { ... / / to empty mCachedViews processDataSetCompletelyChanged (true); // Call requestLayout to refresh the UI if (! mAdapterHelper.hasPendingUpdates()) { requestLayout(); }}}Copy the code
So they will call to RecyclerView# processDataSetCompletelyChanged method: Add FLAG_UPDATE and FLAG_INVALID flags to mChildHelper and mCachedViews ViewHolder. Add ViewHolder in mCachedViews to RecycledViewPool; Empty mCachedViews.
void processDataSetCompletelyChanged(boolean dispatchItemsChanged) { mDispatchItemsChangedEvent |= dispatchItemsChanged; mDataSetHasChangedAfterLayout = true; // Add FLAG_UPDATE and FLAG_INVALID flags to mChildHelper and mCachedViews ViewHolder. Add ViewHolder in mCachedViews to RecycledViewPool; Empty mCachedViews markKnownViewsInvalid (); }Copy the code
RecyclerView# markKnownViewsInvalid method: Add FLAG_UPDATE and FLAG_INVALID to the ViewHolder of mChildHelper. Add FLAG_UPDATE and FLAG_INVALID to the ViewHolder of mChildHelper. Add ViewHolder to RecycledViewPool; Empty mCachedViews
Void markKnownViewsInvalid() {// Add FLAG_UPDATE and FLAG_INVALID to ViewHolder in mChildHelper 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); }}... // Add FLAG_UPDATE and FLAG_INVALID to ViewHolder of mCachedViews and add ViewHolder to RecycledViewPool; Empty mCachedViews mRecycler. MarkKnownViewsInvalid (); }Copy the code
RecyclerView# Recycler# markKnownViewsInvalid method: Add FLAG_UPDATE and FLAG_INVALID to the ViewHolder of mCachedViews and RecycledViewPool; Empty mCachedViews
Void markKnownViewsInvalid() {// Add FLAG_UPDATE and FLAG_INVALID to ViewHolder in mCachedViews 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); // Add mCachedViews ViewHolder to RecycledViewPool; Empty mCachedViews if (mAdapter = = null | |! mAdapter.hasStableIds()) { // we cannot re-use cached views in this case. Recycle them all recycleAndClearCachedViews(); }}Copy the code
conclusion
RecyclerView#setAdapter(); RecyclerView#setAdapter(); RecyclerView#mObserver; MObserver is an instance of RecyclerViewDataObserver. ② Call removeAndRecycleViews method. Remove mAttachedScrap. ③ bind the new Adapter to RecyclerView#mObserver. (4) Notify LayoutManager and RecyclerView of the corresponding data changes.
2, RecyclerView#Adapter#notifyDataSetChanged method call, notify RecyclerView data changes, mainly do the following work: ① Through the observer mode, the observed Adapter informs the observer RecyclerView of the corresponding change. Add FLAG_UPDATE and FLAG_INVALID flags to mChildHelper and mCachedViews ViewHolder in RecyclerView. Add ViewHolder in mCachedViews to RecycledViewPool; Empty mCachedViews. ③ Call requestLayout to refresh the UI.