From: https://blog.csdn.net/wsdaijianjun/article/details/74735039
- <span style="font-size:18px;"> /**
- * RecyclerView can perform several optimizations if it can know in advance that RecyclerView's
- * size is not affected by the adapter contents. RecyclerView can still change its size based
- * on other factors (e.g. its parent's size) but this size calculation cannot depend on the
- * size of its children or contents of its adapter (except the number of items in the adapter).
- * <p>
- * If your use of RecyclerView falls into this category, set this to {@code true}. It will allow
- * RecyclerView to avoid invalidating the whole layout when its adapter contents change.
- *
- * @param hasFixedSize true if adapter changes cannot affect the size of the RecyclerView.
- */
- public void setHasFixedSize(boolean hasFixedSize) {
- mHasFixedSize = hasFixedSize;
- }</span>
Note that when you know that the change of Item in the Adapter will not affect the width and height of RecyclerView, you can set it to true to let RecyclerView avoid recalculating the size.
Set it to true and call notifyDataSetChanged(). It is found that the size has been recalculated. It seems that there is an error in understanding. Let's see where to use this mHasFixedSize.
First, it is used in onMeasure. This is related to the custom LayoutManager, regardless of it.
The rest is the triggerUpdateProcessor() method:
- <span style="font-size:18px;"> void triggerUpdateProcessor() {
- if (POST_UPDATES_ON_ANIMATION && mHasFixedSize && mIsAttached) {
- ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable);
- } else {
- mAdapterUpdateDuringMeasure = true;
- requestLayout();
- }
- }</span>
Take a look at the calls to the triggerUpdateProcessor method
onItemRangeChanged(),
onItemRangeInserted(),
onItemRangeRemoved(),
onItemRangeMoved()
In this way, it is clear that when calling the add, delete, change and insert method of Adapter, the final result will be based on the value of mHasFixedSize to determine whether requestLayout() is needed or not;
Take a look at the code executed by notifyDataSetChanged(). Finally, onChanged is called and requestLayout() is called to measure the width and height again.
- @Override
- public void onChanged() {
- assertNotInLayoutOrScroll(null);
- mState.mStructureChanged = true;
- setDataSetChangedAfterLayout();
- if (!mAdapterHelper.hasPendingUpdates()) {
- requestLayout();
- }
- }
Summary: when we are sure that the change of Item will not affect the width and height of RecyclerView, we can set setHasFixedSize(true), and refresh the RecyclerView through the add, delete, change and insert method of Adapter instead of notifyDataSetChanged(). (in fact, it can be set to true directly. When you need to change the width and height, use notifyDataSetChanged() to refresh the whole.)
- public final void notifyItemChanged(int position) {
- mObservable.notifyItemRangeChanged(position, 1);
- }
- public final void notifyItemChanged(int position, Object payload) {
- mObservable.notifyItemRangeChanged(position, 1, payload);
- }
- public final void notifyItemRangeChanged(int positionStart, int itemCount) {
- mObservable.notifyItemRangeChanged(positionStart, itemCount);
- }
- public final void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) {
- mObservable.notifyItemRangeChanged(positionStart, itemCount, payload);
- }
- public final void notifyItemInserted(int position) {
- mObservable.notifyItemRangeInserted(position, 1);
- }
- public final void notifyItemMoved(int fromPosition, int toPosition) {
- mObservable.notifyItemMoved(fromPosition, toPosition);
- }
- public final void notifyItemRangeInserted(int positionStart, int itemCount) {
- mObservable.notifyItemRangeInserted(positionStart, itemCount);
- }
- public final void notifyItemRemoved(int position) {
- mObservable.notifyItemRangeRemoved(position, 1);
- }
- public final void notifyItemRangeRemoved(int positionStart, int itemCount) {
- mObservable.notifyItemRangeRemoved(positionStart, itemCount);
- }