天天看點

recycleviewitem 清單加載動畫_你真的懂reactnative大清單記憶體優化嗎?

背景

項目中目前大清單控件都是基于FlatList開發的,其中記憶體消耗最大的當屬挑保險頁面,且項目中清單控件使用較頻繁,有必要提高清單的性能。本次優化實踐所有的資料結果都是基于挑保險子產品下的旅遊險欄目測試的,該清單的單行樣式較複雜,清單也較長,可以很好的當做記憶體優化量化名額。測試環境(後續資料都是這個環境):iPhone11模拟器,iOS13.3,release包。現狀:進入挑保險初始記憶體135.5M,清單資料全部加載完(滑到底)163.8M。

cell複用方案

這個是移動端原生開發最正常的優化方案,但是在RN上實踐起來難度不小。目前三方開源庫react-native-largelist-v3就是基于此思路實作的一個大清單元件,其作者也做了大量的測試(号稱永不白闆,性能在百元安卓機(500元紅米)暴力測試通過)。但該庫用在挑保險子產品有如下缺點: 1、該庫的原理其實就是跑馬燈原理:固定數量的元素循環使用,是以布局上必須要開發者指定每行的高度。 2、複用的其實是每行cell的Component,而不像原生那樣其實是複用的cell本身和裡面的所有子視圖。 3、清單滑動太快,複用的cell來不及重新渲染,會有内容閃動現象。 針對以上三點,做了如下嘗試: 1、RN官方的onLayout回調的時機是在控件測繪完成待渲染的時候,但這很明顯無法解決問題一,因為要想拿到這個高度必須得執行個體化cell,這肯定是不能接受的。那有沒有辦法調用RN底層的測量方法呢(measure)? RN底層測量的庫是Yoga,但這個庫使用相當的繁瑣。需要根據cell布局層級建立相應的YogaNode,并且将布局style設定到對應的屬性裡,最後調用measure方法,Yoga庫會自動将計算完的資料在對應的YogaNode中覆寫。而RN引擎正是根據虛拟dom去生成YogaNode(具體可見源碼RCTShadowView,計算後的布局資料也是在這裡面管理的),然後根據計算結果直接渲染了。 綜上所述底層并沒有提供能直接進行數學計算布局的API,也就沒有現成的方法能一鍵算高。是以算高隻能進行手動計算,其實産品清單的cell高度最大的不确定性在于文字的高度,而這個可以通過原生提供算字高度的方法去解決,隻是這樣算高比較麻煩。代碼如下:

recycleviewitem 清單加載動畫_你真的懂reactnative大清單記憶體優化嗎?
recycleviewitem 清單加載動畫_你真的懂reactnative大清單記憶體優化嗎?

2、最大的問題在這裡,因為RN本身的渲染流程導緻無法很完美的去複用cell内部的子元素。我嘗試強制将子元素的React.Element儲存再取出渲染,但這樣子元素的布局和内容重新整理都會受到影響。拖動清單時,新出現的cell都要銷毀舊的子元素,再建立新的子元素。這樣常駐記憶體雖然看起來增長的效果不明顯,但清單整體渲染次數過多,清單滑動過快就會跟不上,是以會出現舊内容閃變成新内容現象。 基于以上的問題和嘗試修複的結果看,cell複用的方式不太适合挑保險這樣的内容複雜的清單。

針對螢幕外的cell的優化處理方案

其實這個官方就有做過處理,FlatList的底層是VirtualizedList,RN官網針對此有詳細的性能優化說明。VirtualizedList的工作原理如下圖所示:

recycleviewitem 清單加載動畫_你真的懂reactnative大清單記憶體優化嗎?

這個圖已經很清楚的展示了優化思路,其實隻要設定合适的initialNumToRender和windowSize即可達到優化效果,但如果windowSize設定過小的話,快速滑動清單會暴露出白色部分。目前挑保險頁面中設定initialNumToRender為10、windowSize設定為5,資料全部加載完記憶體消耗從163M降低至143M,但清單滑動速度達到最高的時候會閃現白色區域,此優化方案還需在滾動速度和windowSize之間作取舍。

總結

由于RN渲染的特殊流程,傳統的原生性能優化思路變得不太可行了,還是需要多多閱讀官方文檔和源碼才行。

相關閱讀:

React深入學習:探究React函數元件和類元件的差別

React Native 中使用Mobx實踐

React Hooks 機制了解與使用(基礎篇)