RecyclerView basic structure
RecyclerView: list container
LayoutManager: layout manager
Recycler: manages the creation, recycling, and reuse of list items
Adapter: used for creation and data binding of list items
ViewHodler: The basic unit of RecyclerView cache, holding ItemView
cache structure
RecyclerView has four levels of cache. The relevant fields are placed in Recycler, the internal class of RecyclerView. They are arranged from left to right according to the cache search order.
ScrapView
Scrap is divided into mAttachedScrap and mChangedScrap. It is a cache list used only in the layout stage. There is no limit on the quantity. Each layout will first put the holder on the screen into scrap. During the layout process, it will be reused from the srcap list. Layout After completion, clear the ViewHolder of this list, and the holders that are not reused will be put into the RecyclerViewPool. The View in Scrap is in the detach state, but has not been removed by the RecyclerView.
mAttachedScrap: holder whose data is invalid (call notify) or the data has not changed. The latter can be reused directly without binding data.
mChangedScrap: ViewHolder whose data has changed, such as the holder that calls notifyItemChanged.
CachedViews
Used in the full life cycle process, which saves the ViewHolder that just slid out of the screen. These holders can be used directly when sliding back without rebinding the data. The default cache number is 2, and more can be obtained under the GapWorker mechanism. Multiple.
ViewCacheExtension
It is used in the full life cycle process. It has no default implementation and can be injected externally. It can only be used to provide ViewHolder. There is no storage logic and basically no usage scenarios. It can be considered to provide preloaded Views.
public abstract static class ViewCacheExtension {
@Nullable
public abstract View getViewForPositionAndType(@NonNull Recycler recycler, int position, int type);
}
RecyclerViewPool
Used in the full life cycle process, ViewHoder is cached according to type. Each type caches 5 by default, which can be set dynamically. After the cache number is exceeded, the excess ViewHolder will be discarded. Supports multiple RecyclerViews to set up the same pool to achieve cross-scenario reuse.
Related mechanisms
StableId
It is used to assign an independent ID to each Item. Its impact is as follows:
When notifyDataSetChange is called in the code, without setting the StableId, since the RecyclerView does not know which holders are valid, all ViewHolders will be recycled to the pool first and then reused from the pool.
When the StableId is set, RecyclerView knows which items are still there, so it will first put all the holders into the scrap list, and then reuse them from the scrap. Only the remaining ones that are not reused will be stored in the pool. . Although this can reduce the reuse process, it also has a pitfall. Before setting stableId, items can be reused as holders in the pool. However, after setting stableId, these holders will not be recycled to the pool, and there is no corresponding type in the pool. holder, a new holder will be created through the adapter, resulting in performance degradation.
GapWorker
A preloading mechanism of RecyclerView that only takes effect in sliding scenarios (drag, inertia, nested sliding). It will pre-prepare the next item (including creation and binding data) based on the sliding direction and distance while the main thread is idle. ), when a sliding occurs, it first calculates the arrival time of the next frame, and then determines whether the ViewHolder can be created before the next frame arrives. If so, it will create the ViewHolder, otherwise it will not create it.
The created Holder will be cached in mCachedView, and the size of the cacheView will be expanded, without extruding the cacheView generated by normal sliding.
Off-screen recycling
#LinearLayoutManager.java
public void setRecycleChildrenOnDetach(boolean recycleChildrenOnDetach) {
mRecycleChildrenOnDetach = recycleChildrenOnDetach;
}
The literal meaning is that when the recyclerView is detached from the parent container, all views are recycled into the RecyclerViewPool. If this RecyclerView shares a pool with other RecyclerViews, it can provide holders for RecyclerViews in other scenes, but this may also cause bugs. , a RecyclerView recycles all items during detach, but does not restore the items when reattaching (the reason is unknown). This results in a blank interface.
Complete reuse process
1. If it is pre-layout (related to animation), find the holder from mChangedScrap, and only need to align the position.
2. Find the holder from mAattchedScrap and mCachedViews. The position needs to be aligned and the data is valid to return (calling notifyxxx will cause the data to become invalid).
3. If the stableId is set, the holdler is searched from the cache list in step 2. The difference from step 2 is that position is no longer used to match the holder, but the id is used. At the same time, it is no longer judged whether the data is valid.
4. Get the holder from ViewCacheExtension (ignored).
5. Get the holder from RecyclerViewPool.
6. Create holder through adapter.
7. If necessary, bind the holder data. (If the holder of notifyxxx is adjusted, it will be called even if stableId is set and the id is consistent.)