Reuse hit flow chart

What is the role of each layer of cache in RecyclerView?

mChangedScrap

The purpose of this layer cache is to cache the location information that has changed after notifyItemChanged(pos),notifyItemRangeChanged(pos,count) is called. Note that mChangedScrap does not mean to store the changed location and reuse it directly. Rather, it stores the changed holder during pre-layout, recreates the new holder and binding data to act as a data refresh for the changed location, and then executes the change animation based on the old and new holders. The new holder will be cached in mRecyclerPool after the animation is completed. How to reuse holder notifyItemChanged(POS) changes? The answer is in mAttachedScrap vs mChangedScrap

mAttachedScrap

The purpose of this layer is to cache items that were not changed when notfyXxx was called, as well as situations affecting the RecyclerView redrawing.

MChangedScrap and mAttachedScrap can be thought of as a hierarchy, with both itemViews visible on the screen, except that the status (changed and unchanged) is distinguished.

mAttachedScrap vs mChangedScrap

In the Recycler class we can see two separate scrap containers: mAttachedScrap and mChangedScrap. Why do you need two?

ViewHolder will only be added to mChangedScrap if: When the associated item changes (notifyItemChanged or notifyItemRangeChanged is called), And call ItemAnimator ViewHolder# canReuseUpdatedViewHolder method, return false. Otherwise, the ViewHolder is added to the mAttachedScrap. CanReuseUpdatedViewHolder returns “false” said we have to perform with a view to replace another view of animation, such as animation fades. “True” indicates that the animation takes place inside the View.

MAttachedScrap can be used throughout the layout, but mChangedScrap can only be used during the pre-layout phase. This makes sense: after the layout, the new ViewHolder should replace the “changed” view, so AttachedScrap is useless after the layout. After the change animation is executed, mChangedScrap will be transferred to mRecyclerPool as expected

You can reuse an updated ViewHolder in three cases:

  1. SetSupportsChangeAnimations (false).
  2. NotifyDataSetChanged instead of notifyItemChanged or notifyItemRangeChanged
  3. AnyObject notifyItemChanged (index).

The last case shows a good way to avoid creating/binding a new ViewHolder when you just want to change some internal elements.

mViewCacheExtension

User – defined cache feels useless.

mCachedViews

In order to avoid multiple bind, is a List of size 2.

mRecyclerPool

When the size of mCachedViews cache is exceeded, the oldest mCachedViews data will be removed and put into mRecyclerPool according to the itemType of the holder set, the default size of the set is 5. Every time a holder is retrieved from mRecyclerPool, the view information needs to be reset. When mRecyclerPool cannot find the cached holder, onCreateViewHolder and onBindViewHolder of the Adapter are called

To predict the animation

Why is the layout executed twice after notifyXxx is called? One pre-layout, one actual layout?

Because RecyclerView is going to do the prediction animation. For example, there are three ItemViews A,B, and C. A and B are loaded on the screen. After deleting B, we will see C move to the position of B. Because we only know where C ends up, but we don’t know where C starts (that is, C hasn’t been loaded yet).

The first pre-layout

Layout all the items in their original state. And according to the Notify information of the Adapter, we know which items are about to change, so we can load another View. In the above example, knowing that B has been deleted, you can load C off screen as well.

The second time, the actual layout, which is the layout after the changes are made.

In this way, as long as you compare the layout changes before and after, you can figure out what animation should be executed, which is called predictive animation.

Refresh the recycle reuse mechanism

We know that notifyXxx will generate RecyclerView twice, one for pre-layout, one for actual layout, and then perform animation operation. The specific execution method is as follows:

  • DispatchLayoutStep1 preliminary layout
  • DispatchLayoutStep2 Actual layout
  • DispatchLayoutStep3 Triggers animation
  1. dispatchLayoutStep1

The change holder is looked for during pre-layout and saved in mChangedScrap; The remaining unchanged will be stored in mAttachedScrap; The following code snippet is used to retrieve the holder in the pre-layout, so the holder information saved by mChangedScrap will only be reused in the pre-layout, and the old holder information will be saved after the pre-layout for executing the change animation in dispatchLayoutStep3

//tryGetViewHolderForPositionByDeadline if (mState.isPreLayout()) { holder = getChangedScrapViewForPosition(position); fromScrapOrHiddenOrCache = holder ! = null; }Copy the code

Other unchanged position holders are obtained from mAttachedScrap

  1. dispatchLayoutStep2

The actual layout, this step creates a new holder and performs the binding data, acting as the holder for the change of position. Because mstate. isPreLayout is false when you perform this step. The holder is then empty, the holder is recreated and the data is bound.

Other locations holder obtained from mAttachedScrap

3.dispatchLayoutStep3

Obtain the old and new holder, execute the change animation, animation after the new holder will be saved in mRecyclerPool.

NotifyDataSetChanged will cause all visible ItemViews in RecyclerView to be removed, and then cached in mRecyclerPool. By default, the maximum cache of each itemType in mRecyclerPool is 5. So when the cache is full, it won’t be cached. Bind (onCreateViewHolder and onBindViewHolder); bind (onCreateViewHolder and onBindViewHolder);

So this explains why notifyItemChanged(pos),notifyItemRangeChanged(pos,count) is more efficient than notifyDataSetChanged.

Sliding recycling reuse mechanism

The cache that slides off the screen is stored in mCachedViews, the default size is 2. If mCachedViews is full, the holder that was first cached by mCachedViews is deleted and stored in mRecyclerPool. Why do I put it in mCachedViews first rather than mRecyclerPool directly, why do I do that?

A layer of mCachedViews cache is added because an itemView that has just slid off the screen may be slid in, and holder retrieved from mCachedViews does not need to be rebind. MRecyclerPool will reset the holder information and re-bind the data.

conclusion

MChangedScrap, mAttachedScrap is for recycling and reuse when the screen visible itemView information changes

MCachedViews and mRecyclerPool are aimed at sliding recycling and reuse

Also can be set by setItemViewCacheSize mCachedViews cache size, can be achieved by recycledViewPool. SetMaxRecycledViews () modify mRecyclerPool cache size

Refer to the connection

Deep understanding of RecyclerView cache mechanism

RecyclerView cache and optimization – understand