A brief analysis of the internal workflow of notifyDataSetChanged

First of all, we know that notifyDataSetChanged is a method of Adater. It is mainly used to notify ListView and tell it that the data of Adapter has changed and the display of ListView needs to be updated. Therefore, when the data content of Adapter changes, notifyDataSetChanged() method will be called.
Take a look directly at the source code implementation of notifyDataSetChanged in BaseAdapter to see how notifyDataSetChanged works.

public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
    private final DataSetObservable mDataSetObservable = new DataSetObservable();

    public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged();
    }
}

You can see that it calls notifyChanged in DataSetObservable. Go to DataSetObservable to view the implementation.

public class DataSetObservable extends Observable<DataSetObserver> {
        public void notifyChanged() {
        synchronized(mObservers) {

            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();
            }
        }
    }
}

mObervers is defined in the parent class Observable of DataSetObservable:

public abstract class Observable<T> {

    protected final ArrayList<T> mObservers = new ArrayList<T>();

}

It is an ArrayList of DataSetObserver type, and the onChange function of DataSetObserver is ultimately executed.

Let’s take a look at the source code of the DataSetOberver class:

public abstract class DataSetObserver {

    public void onChanged() {
        // Do nothing
    }

      public void onInvalidated() {
        // Do nothing
    }
}

It can be roughly seen from the above process that if you need to be notified of ListView updates, first implement a DataSetObserver class, rewrite the onChanged callback method, and then add (register) this object to the ArrayList, so that when we call notifyDataSetChanged , it will traverse this ArrayList to take out the DataSetObserver object and call back the onChanged method. In other words, our final work of refreshing ListViewd should be in this onChanged method.

Then the question is where the system implements a DataSetObserver class, overrides the onChanged callback method, and then adds this object to the ArrayList.

In fact, this work is done in setAdapter. When setting an Adapter for ListView, a callback listener is registered in the Adapter, which is to implement a DataSetObserver class as mentioned above, rewrite the onChanged callback method, and then add this The object is added to the ArrayList. When the Adapter calls notifyDataSetChanged, the onChanged function will be called back and the ListView will be updated in onChanged, so that the ListView will be updated.

So let’s take a look at the implementation of setAdapter in ListAdapter:

@Override
    public void setAdapter(ListAdapter adapter) {
        //Here to determine whether the listener has been registered
        //If already registered, cancel registration
        //If setAdapter is called repeatedly, the following code will execute mDataSetObserver to remove it from the ArrayList
        if (mAdapter != null & amp; & amp; mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }

        resetList();
        mRecycler.clear();

        if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
            mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
        } else {
            mAdapter = adapter;
        }

        mOldSelectedPosition = INVALID_POSITION;
        mOldSelectedRowId = INVALID_ROW_ID;

        // AbsListView#setAdapter will update choice mode states.
        super.setAdapter(adapter);

        if (mAdapter != null) {
            mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
            mOldItemCount = mItemCount;
            //Get the number of data
            mItemCount = mAdapter.getCount();
            checkFocus();

            //See if there is an AdapterDataSetObserver defined here, which is the implementation class of DataSetObserver
            mDataSetObserver = new AdapterDataSetObserver();
            //You should understand when you see this. Here, the class object implemented by DataSetObserver is added to the ArrayList so that it can be called back.
            mAdapter.registerDataSetObserver(mDataSetObserver);

            mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());

            int position;
            if (mStackFromBottom) {
                position = lookForSelectablePosition(mItemCount - 1, false);
            } else {
                position = lookForSelectablePosition(0, true);
            }
            setSelectedPositionInt(position);
            setNextSelectedPositionInt(position);

            if (mItemCount == 0) {
                // Nothing selected
                checkSelectionChanged();
            }
        } else {
            mAreAllItemsSelectable = true;
            checkFocus();
            // Nothing selected
            checkSelectionChanged();
        }

        //Will cause the measure() process and layout() process to be called
        requestLayout();
    }

For specific explanations, please refer directly to the comments of the code, which is easier to understand. The main ones are mDataSetObserver = new AdapterDataSetObserver() and mAdapter.registerDataSetObserver(mDataSetObserver). We have commented above that AdapterDataSetObserver is the implementation class of DataSetObserver, which overrides onChanged method.
Looking at the AdapterDataSetObserver source code, you can see here what the final operation of notifyDatasetChanged is, because it finally calls back the onChanged method. AdapterDataSetObserver is an internal class of AbsListView

class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
        @Override
        public void onChanged() {
            //Here is the core operation
            super.onChanged();
            if (mFastScroller != null) {
                mFastScroller.onSectionsChanged();
            }
        }

        @Override
        public void onInvalidated() {
            super.onInvalidated();
            if (mFastScroller != null) {
                mFastScroller.onSectionsChanged();
            }
        }
    }

The final callback is the onChanged function here. Look directly at the code. The core operation is in super.onChanged().
super.onChanged means executing the onChanged function in AdapterView.AdapterDataSetObserver, which is an internal class of ApdaterView.

class AdapterDataSetObserver extends DataSetObserver {

        private Parcelable mInstanceState = null;

        @Override
        public void onChanged() {
            mDataChanged = true;
            mOldItemCount = mItemCount;
            mItemCount = getAdapter().getCount();

            // Detect the case where a cursor that was previously invalidated has
            // been repopulated with new data.
            if (AdapterView.this.getAdapter().hasStableIds() & amp; & amp; mInstanceState != null
                     & amp; & amp; mOldItemCount == 0 & amp; & amp; mItemCount > 0) {
                AdapterView.this.onRestoreInstanceState(mInstanceState);
                mInstanceState = null;
            } else {
                rememberSyncState();
            }
            checkFocus();
            //Will cause the measure() process and layout() process to be called
            requestLayout();
        }

        @Override
        public void onInvalidated() {
            mDataChanged = true;

            if (AdapterView.this.getAdapter().hasStableIds()) {
                // Remember the current state for the case where our hosting activity is being
                // stopped and later restarted
                mInstanceState = AdapterView.this.onSaveInstanceState();
            }

            // Data is invalid so we should reset our state
            mOldItemCount = mItemCount;
            mItemCount = 0;
            mSelectedPosition = INVALID_POSITION;
            mSelectedRowId = INVALID_ROW_ID;
            mNextSelectedPosition = INVALID_POSITION;
            mNextSelectedRowId = INVALID_ROW_ID;
            mNeedSync = false;

            checkFocus();
            requestLayout();
        }

        public void clearSavedState() {
            mInstanceState = null;
        }
    }

See, this class implements DataSetObserver, which just explains the above statement. Just look at its onChanged function. Just look at the last sentence requestLayout(), it will be refreshed here.
If you are careful, you should also see that this function is also executed in setAdapter. This fully explains that when this function is executed, layout and redrawing are performed here.
One thing we can know here is that the refresh of ListView we faced above is essentially calling the requestLayout method.