前言
本文是在作者Blankj基礎(chǔ)上補(bǔ)充一些RecyclerView的正確姿勢Tips 持續(xù)更新~
數(shù)據(jù)處理和視圖加載分離
我們知道,從遠(yuǎn)端拉取數(shù)據(jù)肯定是要放在異步的混埠,在我們拉取下來數(shù)據(jù)之后可能就匆匆把數(shù)據(jù)丟給了 VH 處理誓酒,其實(shí),數(shù)據(jù)的處理邏輯我們也應(yīng)該放在異步處理貌亭,這樣 Adapter 在 notify change 后柬唯,ViewHolder 就可以簡單無壓力地做數(shù)據(jù)與視圖的綁定邏輯,比如:
mTextView.setText(Html.fromHtml(data).toString());
這里的 Html.fromHtml(data)
方法可能就是比較耗時(shí)的圃庭,存在多個(gè) TextView
的話耗時(shí)會更為嚴(yán)重锄奢,這樣便會引發(fā)掉幀美尸、卡頓,而如果把這一步與網(wǎng)絡(luò)異步線程放在一起斟薇,站在用戶角度师坎,最多就是網(wǎng)絡(luò)刷新時(shí)間稍長一點(diǎn)。
數(shù)據(jù)優(yōu)化
分頁拉取遠(yuǎn)端數(shù)據(jù)堪滨,對拉取下來的遠(yuǎn)端數(shù)據(jù)進(jìn)行緩存胯陋,提升二次加載速度;對于新增或者刪除數(shù)據(jù)通過 DiffUtil
來進(jìn)行局部刷新數(shù)據(jù)袱箱,而不是一味地全局刷新數(shù)據(jù)遏乔。
布局優(yōu)化
減少過渡繪制
減少布局層級,可以考慮使用自定義 View 來減少層級发笔,或者更合理地設(shè)置布局來減少層級盟萨,不推薦在 RecyclerView 中使用 ConstraintLayout
,有很多開發(fā)者已經(jīng)反映了使用它效果更差了讨,相關(guān)鏈接有:Is ConstraintLayout that slow?捻激、constraintlayout 1.1.1 not work well in listview。
減少 xml 文件 inflate 時(shí)間
這里的 xml 文件不僅包括 layout 的 xml前计,還包括 drawable 的 xml胞谭,xml 文件 inflate 出 ItemView 是通過耗時(shí)的 IO 操作,尤其當(dāng) Item 的復(fù)用幾率很低的情況下男杈,隨著 Type 的增多丈屹,這種 inflate 帶來的損耗是相當(dāng)大的,此時(shí)我們可以用代碼去生成布局伶棒,即 new View()
的方式旺垒,只要搞清楚 xml 中每個(gè)節(jié)點(diǎn)的屬性對應(yīng)的 API 即可。
減少 View 對象的創(chuàng)建
一個(gè)稍微復(fù)雜的 Item 會包含大量的 View肤无,而大量的 View 的創(chuàng)建也會消耗大量時(shí)間先蒋,所以要盡可能簡化 ItemView;設(shè)計(jì) ItemType 時(shí)舅锄,對多 ViewType 能夠共用的部分盡量設(shè)計(jì)成自定義 View鞭达,減少 View 的構(gòu)造和嵌套。
其他
其他并不代表不重要皇忿,而是我不能把他們進(jìn)行分類哈畴蹭,其中可能某些操作會對你的 RecyclerView 有很大的優(yōu)化。
升級
RecycleView
版本到 25.1.0 及以上使用 Prefetch 功能鳍烁,可參考 RecyclerView 數(shù)據(jù)預(yù)取叨襟。如果 Item 高度是固定的話,可以使用
RecyclerView.setHasFixedSize(true);
來避免requestLayout
浪費(fèi)資源幔荒;設(shè)置
RecyclerView.addOnScrollListener(listener);
來對滑動(dòng)過程中停止加載的操作糊闽。如果不要求動(dòng)畫梳玫,可以通過
((SimpleItemAnimator) rv.getItemAnimator()).setSupportsChangeAnimations(false);
把默認(rèn)動(dòng)畫關(guān)閉來提神效率。對
TextView
使用String.toUpperCase
來替代android:textAllCaps="true"
右犹。對
TextView
使用StaticLayout
或者DynamicLayout
的自定義View
來代替它提澎。通過重寫
RecyclerView.onViewRecycled(holder)
來回收資源。通過
RecycleView.setItemViewCacheSize(size);
來加大RecyclerView
的緩存念链,用空間換時(shí)間來提高滾動(dòng)的流暢性盼忌。如果多個(gè)
RecycledView
的Adapter
是一樣的,比如嵌套的RecyclerView
中存在一樣的Adapter
掂墓,可以通過設(shè)置RecyclerView.setRecycledViewPool(pool);
來共用一個(gè)RecycledViewPool
谦纱。對
ItemView
設(shè)置監(jiān)聽器,不要對每個(gè) Item 都調(diào)用addXxListener
君编,應(yīng)該大家公用一個(gè)XxListener
跨嘉,根據(jù)ID
來進(jìn)行不同的操作,優(yōu)化了對象的頻繁創(chuàng)建帶來的資源消耗吃嘿。-
通過 getExtraLayoutSpace 來增加 RecyclerView 預(yù)留的額外空間(顯示范圍之外祠乃,應(yīng)該額外緩存的空間),如下所示:
new LinearLayoutManager(this) { @Override protected int getExtraLayoutSpace(RecyclerView.State state) { return size; } };
高度盡量設(shè)置為match_parent ,wrap_content的AT_MOST測量模式會使RecyclerView遍歷測量子View的高度,造成不必要的內(nèi)存開銷唠椭。
優(yōu)先使用多布局,如果非要被
ScrollView
嵌套的RecyclerView
應(yīng)該再嵌套一層RelativeLayout
避免再某些機(jī)型中導(dǎo)致RecyclerView
顯示不完全跳纳,該設(shè)置android:nestedScrollingEnabled="false"
可以解決RecyclerView
被嵌套后滑動(dòng)不流暢。
<RelativeLayout
android:descendantFocusability="blocksDescendants"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.recyclerview.widget.RecyclerView
android:nestedScrollingEnabled="false"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>