當前位置:首頁 » 文件管理 » recyclerview緩存

recyclerview緩存

發布時間: 2023-02-26 02:05:02

A. Recyclerview多種場景下的優化

因為APP設計的原因,Recyclerview是我在Android中最常用的組件,我們公司的APP幾乎每一個頁面都會包含至少一個Recyclerview,本篇文章主要介紹一些我個人在工作中總結、收集的recyclerview優化經驗。

1.不要在onBindViewHolder中設置點擊事件和耗時操作

Recyclerview的onBindViewHoler主要負責將數據與holder綁定,它在列表滑動時會不停的被調用。如果在onBindViewHolder中設定監聽操作,會導致已經的綁定點擊事件的view,被重復綁定監聽操作。

點擊事件的監聽可以在onCreateViewHolder中設定。一些會創建新對象的操作,也需要根據實際情況考慮從onBindViewHolder中遷移到onCreateViewHolder。

注意: onBindViewHolder運行在UI線程中,如果進行了耗時操作,會導致頁面卡頓。並且onBindViewHolder中只應該進行數據的綁定,而不應該進行數據的處理和計算等操作。

2.Recyclerview嵌套Recyclerview的優化

Recyclerview嵌套Recyclerview最經典的運用就是,一個縱向滑動的列表內部的每個item是一個可以橫向滑動的Recyclerview,比如說GooglePlay。

這種情況可以使用LinearLayoutManager.setInitialPrefetchItemCount()設定
橫向列表初次顯示時可見item的個數。如果橫向滑動的View中數據量很少,並且不需要橫向刷新時,也可以考慮使用HorizontalScrollView實現。

關於這個API的官方文檔翻譯如下:

如果將此值設置為大於此視圖中可見的視圖數可能會導致不必要的綁定工作,並且會增加創建和活動使用的視圖數。

3.多個RecycerView共用RecycledViewPool

在大多數APP中都有這樣一種場景,一個ViewPager中包含多個Fragment,而Fragment中主體是Recyclerview,並且Recyclerview中item view的布局是相同的。例如 微博等

這種情況下,Recyclerview可以設定統一的緩存池用來提高性能。

新建緩存池:

設定緩存池:

4.精確的更新數據使用DiffUtil

在Recyclerview中提供了多種數據數據刷新方式

雖然有了這些刷新方式,但是實際開發中,存在這樣一種情況,新數據集與舊數據集僅有一部分數據存在差異。

例如:刷新一個聯系人列表,聯系人列表中部分聯系人的頭像有變化,但是姓名和手機號碼等信息未發生變化。這種情況以往都是使用notifyDataChanged方法刷新全部數據,但是刷新全部數據的會導致整個布局重繪,Recyclerview中針對這種情況還提供了另一種粒度更小的刷新方式 DiffUti

這里不打算去講DiffUtil的具體用法,只需要記住DiffUtil的使用場景即可: 列表中存在多個Item的數據需要刷新,但是新數據集與舊數據集存在重復的情況

5.靈活設定setHasFixedSize
在Recyclerview中使用以下方法時,會觸發requestLayout()

requestLayout()會重新計算item的大小,如果item的布局文件已經將寬高設為固定大小,可以設定setHasFixedSize(true),來避免Recyclerview重新計算item的大小。

6.優化Item的布局
布局優化是個老生長談的問題,本質上就是減少嵌套,ConstraintLayout是google推出的一個用於減少布局嵌套的新layout,但是在Recyclerview中使用ConstraintLayout會導致cpu使用率上升,暫時不推薦使用,不過ConstraintLayout 2.0版本已經進入beta測試,期待後續會有優化。

7.數據非常少時,使用ListView
不知道你有沒有考慮過這樣的問題,RecyclerView用已經如此強大,用得人也越來越多,為什麼最新的Android系統中ListView依然沒有被標注為"過時"。
RecyclerView重新設計了緩存機制,新的緩存機制更加強大,更適合處理大量數據的顯示,但是這種緩存機制會占據更多的內存,當一個列表頁面實際數據項非常少的時候,ListView往往比RecyclerView更合適。

B. recycleview一行多個時,會全部緩存嗎

會。
首先說下RecycleView的緩存結構,Recycleview有四級緩存,分別是mAttachedscrap(屏幕內),mCacheviews(屏幕外),mViewcacheextension(自定義緩存),mRecyclerpool(緩存池)mAttachedscrap(屏幕內)用於屏幕內itemview快速重用,不需要重新createview和bindview,mCacheviews(屏幕外)保存最近移出屏幕的Viewholder,包含數據和position信息,復用時必須是相同位置的Viewholder才能復用,應用場景在那些需要來回滑動的列表中,當往回滑動時,能直接復用Viewholder數據,不需要重新bindview。mViewcacheextension(自定義緩存),不直接使用,需要用戶自定義實現,默認不實現。mRecyclerpool(緩存池),當cacheview滿了後或者adapter被更換,將cacheview中移出的Viewholder放到Pool中,放之前會把Viewholder數據清除掉,所以復用時需要重新bindview。當recycleview一行多個時,recycleview的四級緩存機制支持全部緩存。
Recyclerview的緩存機制還是非常值得到家參考的,先來說一下Recyclerview關於緩存的方法,關於Recyclerview的緩存數據有兩個級別,一個是detach,另一個就是remove,關於detach就是在Recyclerview滑動或者layout時為了記錄屏幕內條目信息而設定的,他主要的緩存的數據就是getchildcount列表所持有的數據,至於remove就是為了緩存我們從數據列表所刪除的數據,根據這個信息我們可從代碼來分析。

C. RecyclerView緩存原理及優化方向

Android新增的Recyclerview主要用於代替ListView。Recyclerview可擴展性強。

RecyclerView做性能優化要說復雜也復雜,比如說布局優化,緩存,預載入等等。

其優化的點很多,在這些看似獨立的點之間,其實存在一個樞紐:Adapter。

因為所有的ViewHolder的創建和內容的綁定都需要經過Adaper的兩個函數 onCreateViewHolder和onBindViewHolder 。

因此我們性能優化的本質就是要 **減少這兩個函數的調用時間和調用的次數** 。

如果我們想對RecyclerView做性能優化,必須清楚的了解到我們的每一步操作背後,onCreateViewHolder和onBindViewHolder調用了多少次。

因此,了解RecyclerView的緩存機制是RecyclerView性能優化的基礎。

為了簡化問題,繪制原理介紹提供以下假設:

(1)類的職責介紹
LayoutManager:接管RecyclerView的Measure,Layout,Draw的過程

Recycler:緩存池

Adapter:ViewHolder的生成器和內容綁定器。

(2)繪制過程簡介

RecyclerView緩存基本上是通過三個內部類管理的, Recycler 、 RecycledViewPool 和 ViewCacheExtension 。
Recycler
用於管理已經廢棄或者與RecyclerView分離的ViewHolder,為了方便理解這個類,整理了下面的資料,內部類的成員變數和他們的含義:

RecycledViewPool
RecycledViewPool類是用來緩存Item用,是一個ViewHolder的緩存池,如果多個RecyclerView之間用 setRecycledViewPool(RecycledViewPool) 設置同一個RecycledViewPool,他們就可以共享Item。
其實RecycledViewPool的內部維護了一個Map,裡面以不同的viewType為Key存儲了各自對應的ViewHolder集合。可以通過提供的方法來修改內部緩存的Viewholder。
ViewCacheExtension
開發者可自定義的一層緩存,是虛擬類ViewCacheExtension的一個實例,開發者可實現方法getViewForPositionAndType(Recycler recycler, int position, int type)來實現自己的緩存。

屏幕內緩存指在屏幕中顯示的ViewHolder,這些ViewHolder會緩存在mAttachedScrap、mChangedScrap中 :

當列表滑動出了屏幕時,ViewHolder會被緩存在 mCachedViews ,其大小由mViewCacheMax決定,默認DEFAULT_CACHE_SIZE為2,可通過Recyclerview.setItemViewCacheSize()動態設置。

可以自己實現ViewCacheExtension類實現自定義緩存,可通過Recyclerview.setViewCacheExtension()設置。

ViewHolder在首先會緩存在 mCachedViews 中,當超過了個數(比如默認為2), 就會添加到 RecycledViewPool 中。
在有限的mCachedViews中如果存不下ViewHolder時,就會把ViewHolder存入RecyclerViewPool中。
* 按照Type來查找ViewHolder
* 每個Type默認最多緩存5個

RecycledViewPool 會根據每個ViewType把ViewHolder分別存儲在不同的列表中,每個ViewType最多緩存DEFAULT_MAX_SCRAP = 5 個ViewHolder,如果RecycledViewPool沒有被多個RecycledView共享,對於線性布局,每個ViewType最多隻有一個緩存,如果是網格有多少行就緩存多少個。

Recyclerview在獲取ViewHolder時按四級緩存的順序查找,如果沒找到就創建。其中只有RecycledViewPool找到時才會調用 bindViewHolder,其它緩存不會重新bindViewHolder 。

通過了解RecyclerView的四級緩存,我們可以知道,RecyclerView最多可以緩存 N(屏幕最多可顯示的item數) + 2 (屏幕外的緩存) + 5*M (M代表M個ViewType,緩存池的緩存),只有RecycledViewPool找到時才會重新調用 bindViewHolder。

RecyclerView在Recyler裡面實現ViewHolder的緩存,Recycler裡面的實現緩存的主要包含以下5個對象:

RecyclerView在設計的時候講上述5個緩存對象分為了3級。
每次創建ViewHolder的時候,會按照優先順序依次查詢緩存創建ViewHolder 。
三級緩存分別是:

RecyclerView緩存原理,有圖有真相
關於Recyclerview的緩存機制的理解

D. 談談RecyclerView中的緩存

Android深入理解RecyclerView的緩存機制

RecyclerView在項目中的使用已經很普遍了,可以說是項目中最高頻使用的一個控制項了。除了布局靈活性、豐富的動畫,RecyclerView還有優秀的緩存機制,本文嘗試通過源碼深入了解一下RecyclerView中的緩存機制。

RecyclerView做性能優化要說復雜也復雜,比如說布局優化,緩存,預載入等等。其優化的點很多,在這些看似獨立的點之間,其實存在一個樞紐:Adapter。因為所有的ViewHolder的創建和內容的綁定都需要經過Adaper的兩個函數onCreateViewHolder和onBindViewHolder。

因此我們性能優化的本質就是要減少這兩個函數的調用時間和調用的次數。如果我們想對RecyclerView做性能優化,必須清楚的了解到我們的每一步操作背後,onCreateViewHolder和onBindViewHolder調用了多少次。因此,了解RecyclerView的緩存機制是RecyclerView性能優化的基礎。

為了理解緩存的應用場景,本文首先會簡單介紹一下RecyclerView的繪制原理,然後再分析其緩存實現原理。

RecyclerView滑動時會觸發onTouchEvent#onMove,回收及復用ViewHolder在這里就會開始。我們知道設置RecyclerView時需要設置LayoutManager,LayoutManager負責RecyclerView的布局,包含對ItemView的獲取與復用。以LinearLayoutManager為例,當RecyclerView重新布局時會依次執行下面幾個方法:

上述的整個調用鏈:onLayoutChildren()->fill()->layoutChunk()->next()->getViewForPosition(),getViewForPosition()即是是從RecyclerView的回收機制實現類Recycler中獲取合適的View,下面主要就來從看這個Recycler#getViewForPosition()的實現。

上述邏輯用流程圖表示:

RecyclerView在Recyler裡面實現ViewHolder的緩存,Recycler裡面的實現緩存的主要包含以下5個對象:

public final class Recycler {

final ArrayList mAttachedScrap = new ArrayList<>();

ArrayList mChangedScrap = null;

RecyclerView在設計的時候講上述5個緩存對象分為了3級。每次創建ViewHolder的時候,會按照優先順序依次查詢緩存創建ViewHolder。每次講ViewHolder緩存到Recycler緩存的時候,也會按照優先順序依次緩存進去。三級緩存分別是:

使用自定義ViewCacheExtension後,view離屏後再回來不會走onBindViewHolder()方法。

holder.setIsRecyclable(false),這樣的話每次都會走onCreateViewHolder()和onBindViewHolder()方法

1.提前初始化viewHolder,放到緩存池中

viewPool.putRecycledView(adapter.onCreateViewHolder(recyclerView, 1))

2.提前初始化view,在onCreateViewHolder的時候去取view

3.自定義ViewCacheExtension

4.適當的增加cacheSize

4.公用緩存池,比如多個viewPager+fragment場景使用,或者全局單利緩存池,感覺用戶不大。

有2中做法有值

第一種

第二種

不會,因為prefetch(GapWorker中的一個方法)之後mViewCacheMax會變成mRequestedCacheMax + extraCache

有2種方式可以讓緩存失效

第一種

recyclerView.setItemViewCacheSize(-1)

第二種

recyclerView.setItemViewCacheSize(0)

layoutManager.isItemPrefetchEnabled = false

設置不緩存後,來回滑動讓view進入屏幕離開屏幕,viewHolder的item時會多次走onBindViewHolder()方法。

熱點內容
可編程式恆溫恆濕試驗箱 發布:2025-05-20 04:54:34 瀏覽:366
visibilityandroid 發布:2025-05-20 04:54:26 瀏覽:698
android磁場感測器 發布:2025-05-20 04:50:46 瀏覽:827
python經典編程題 發布:2025-05-20 04:42:33 瀏覽:782
xp電腦訪問win7 發布:2025-05-20 04:41:59 瀏覽:617
金融的配置是什麼 發布:2025-05-20 04:41:07 瀏覽:466
解壓擠耳朵 發布:2025-05-20 04:37:02 瀏覽:887
QP演算法包 發布:2025-05-20 04:31:54 瀏覽:969
ps3連ftp 發布:2025-05-20 04:19:11 瀏覽:818
計算機編譯干什麼的 發布:2025-05-20 04:05:18 瀏覽:47