RecyclerView是Android平台上非常流行的一個控件,用於展示列表數據。它是ListView的升級版,優化了性能和擴展性。其中最重要的一項優化就是緩存機制,這使得RecyclerView更具有高效性。
一、緩存機制概述
RecyclerView中的緩存機制,是指它的item View的緩存。它緩存了RecyclerView中所有item View的實例,不再每次滾動列表時都去創建新的實例,大大減少了耗時和消耗內存。
RecyclerView的緩存機制主要有兩種形式:可復用的緩存池和不可復用的緩存池。
二、可復用的緩存池
RecyclerView將創建的item View存儲在一個可復用的緩存池中,這個緩存池用於存儲所有已離開屏幕(滑出屏幕)的item View。當需要展示一個新的item View時,RecyclerView先從緩存池中查找可復用的item View,如果找到了就直接使用,如果沒有找到就創建新的item View。
1、緩存池的實現
public class RecyclerView{ ... final Recycler mRecycler = new Recycler(); ... class Recycler { ... private ArrayList mAttachedScrap = new ArrayList(); private ArrayList mCachedViews = new ArrayList(); ... } ... }
RecyclerView的緩存池實現在Recycler類中,緩存池主要有兩個ArrayList,分別是mAttachedScrap和mCachedViews。
其中,mAttachedScrap是一個臨時緩存池,用於存儲RecyclerView中所有已離開屏幕的item View;mCachedViews是一個可復用的緩存池,用於存儲所有已經被detach(移除父View)的item View。
2、視圖回收機制
RecyclerView的視圖回收機制,會在item View離開屏幕後,將item View存儲在mAttachedScrap中,等待重新使用。每次滾動列表時,會調用RecyclerView的scrollBy()方法,檢測所有在屏幕外的item View,將其放置在mAttachedScrap中。同時,在Recycler類中提供了一個方法,用於清空mAttachedScrap中的所有item View:
void clear() { mAttachedScrap.clear(); recycleAndClearCachedViews(); }
三、不可復用的緩存池
在item View因為屏幕滑動被移除屏幕時,RecyclerView並不會將其直接放入mCachedViews緩存池中。而是將這些不可復用的item View標記為「Scrap」,並將它們存儲在Recycler中的mChangedScrap中。這些不可復用的item View只能在下次重新創建新的item View之前使用,因為它們的ViewHolder會被重新創建,所有緩存失效。
1、不可復用的緩存池實現
class Recycler { ... ArrayList mChangedScrap = null; int mViewCacheMaxCount = DEFAULT_CACHE_SIZE; ... }
RecyclerView的不可復用的緩存池是mChangedScrap ArrayList,用於存儲當前屏幕之外的item View,該緩存池的最大容量受到一個參數mViewCacheMaxCount限制,其默認值是2。
2、Scrap機制實現
RecyclerView的Scrap機制主要包含3個過程:
- 在Recycler的detachAndScrapAttachedViews()方法中,將除了第一個可視的Item以外的所有Item View從RecyclerView中detach(移除父View),並將其存儲在mChangedScrap中。
- 在Recycler的getViewForPosition()方法中,首先會從可復用的緩存池mCachedViews中查找是否有可復用的item View。如果沒有,就從mAttachedScrap中查找。
- 如果mAttachedScrap中也沒有可復用的item View,那麼就從mChangedScrap中查找是否有不可復用的item View。如果找到了,就將其重新bind(綁定數據)。如果沒有找到,就創建全新的item View。
四、對緩存機制的優化
為了提高RecyclerView的性能,可以對緩存機制進行優化:
1、手動保持ViewHolder的狀態
ViewHolder是item View的持有者,保存着item View中的子View的引用,因此ViewHolder內部的狀態不像item View那樣容易受到RecyclerView的狀態改變而改變。在View的復用時,可能會引發一些問題。在ViewHolder中存儲該View的狀態信息,可以解決這類問題。我們可以在ViewHolder中添加一個保存狀態的SparseArray,存儲着每一個子View的狀態信息。在onBindViewHolder()方法中,將保存的狀態賦值給子View即可。
2、減少item View的層級結構
RecyclerView的性能也受到item View的層級結構的影響。當一個item View中含有嵌套的子View層級較多的時候,就容易引起過度繪製、卡頓等問題,降低了RecyclerView的性能。因此,為了提高RecyclerView的性能,item View的層級結構應該儘可能的簡單。
3、減小item View的尺寸與數量
RecyclerView的性能受到item View的數量和尺寸的影響,如果item View尺寸太小,數量太多,RecyclerView的性能將會變得很低。因此,我們需要儘可能的減少item View的數量,增加item View的尺寸。另外,設置item View儘可能的大,可以減少item View與布局之間的間隙,使屏幕不容易產生過度繪製。
五、總結
RecyclerView的緩存機制是其性能的重要保證之一。RecyclerView通過可復用的緩存池和不可復用的緩存池,實現了對item View的緩存,避免了每次滾動列表時都去創建新的實例。同時,通過手動保持ViewHolder的狀態、減少item View的層級結構和數量、減小item View的尺寸,可以進一步提高RecyclerView的性能。
原創文章,作者:RKETI,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/351647.html