構建高性能 React Native 跨端應用—圖片與內存
一 前言
在構建高性能 React Native 跨端應用—引擎與渲染章節中,我們從引擎與渲染角度介紹了 React Native 的優化手段,本文我們繼續從圖片和內存角度繼續討論一下如何構建高性能的 React Native 應用。
二 圖像層面
在瀏覽器構建的 web 中開發者可能不用花費太多精力關注圖像上,但是在移動應用中,對於圖像的關注顯得非常重要。因爲在 RN 應用中,無論是圖片還是動圖,或者是視頻都是非常耗內存的,內存的暴漲就很容易造成應用的崩潰。
圖片合理應用
圖片的處理,佔 RN 性能優化的大頭,在現在的移動端應用中,有很多應用大量圖片的場景,加載圖片的過程實際是很複雜的,並且圖片本身的大小,也不是最後加載到內存中的大小,也就是說最後落實在內存裏面的大小,會大於圖片本身的大小。
圖片的處理在不同平臺上表現也不一致,在 iOS 平臺上對於圖像的加載,加密,到最後的展現,表現還算比較好。但是在安卓平臺,就時常會出現幺蛾子。
筆者在開發 RN 應用中,就遇到了這樣的場景:我們 RN 只運行在安卓端,一個 RN 頁面會加載大量的圖片,剛開始我們沒有對圖片進行任何處理,只是圖片的寬度和高度是寫死的,那麼造成的現象是,所有的圖片都展現不出來,並且圖片是黑的,接下來就是安卓程序直接崩潰。
後來經過排查我們發現,原來我們給圖片的容器特別小,但是圖片資源卻非常大,由於爲了在小容器中呈現大的圖片,就比如說一個 100 * 100 圖片容器,加載一個 1000 * 1000 圖片,安卓底層需要對圖片源數據進行算法壓縮,此時就會讓內存暴漲,幀率直接降爲個位數,導致黑屏,閃退的情況。筆者還把這種小容器加載大圖片的情況,叫做小馬拉大車。
那麼如何解決這個問題呢? RN 中的 Image 組件有個 resizeMethod 屬性,就是解決 Android 圖片內存暴漲的問題。當圖片實際尺寸和容器樣式尺寸不一致時,決定以怎樣的策略來調整圖片的尺寸。
<Image resizeMethod="resize" source={{ uri: imageUrl }} />
resizeMethod 屬性有三個可選的值,默認爲 auto .
resize:小容器加載大圖的場景就應該用這個屬性。原理是在圖片解碼之前,會用算法對其在內存中的數據進行修改,一般圖片大小大概會縮減爲原圖的 1/8。 scale:不改變圖片字節大小,通過縮放來修改圖片寬高。因爲有硬件加速,所以加載速度會更快一些。
auto:使用啓發式算法來在 resize 和 scale 中自動決定,,如果是本地圖片,就會用 resize,其他的一般都是 scale 屬性,由於項目運用的是網絡圖片,所以就按照 scale 處理邏輯。
實際最佳的方案就是,適當的大小的圖片容器,加載適當的圖片。但是對於一些圖片資源的大小是未知的,我們不能直接通過設置寬和高的方式草率的設置圖片容器大小,解決方案就是可以通過 api 的方式獲取遠程圖片的大小。如下:
import { Image } from 'react-native'
/* 使用 */
Image.getSize(imageUrl,(width,height)=>{
console.log('寬度:',width,'高度:',height)
})
當然客戶端也可以把圖片壓縮的操作交給服務端去做,目前很多大公司都有自己的內建圖牀和 CDN 服務,會提供一些自定製圖片的功能,在請求圖片資源的時候,就把圖片的寬和高拼接到 url 中,這樣服務器接受到圖片請求,會根據路徑獲取 width 和 height,然後自行的對圖片進行壓縮。返回給客戶端的就已經是處理好的能夠適配圖片容器大小的圖片了。
圖片管理優化
上面介紹了圖片的合理使用,接下來我們看一下圖片的管理優化,在 RN 中有多種多樣的類型的圖片,比如 png/jpg/base64/gif ,對於 gif 在安卓 build.gradle 中需要添加相關依賴。對於一些動圖的處理,比如 svg 和 svga ,RN 也提供了相關的生態去處理這些圖像。
對圖片的管理可以通過不同的場景,運用更爲合理的方案。比如對於一些大量 gif 圖片的場景,內存就是一個棘手問題,圖片的管理工具就需要均衡好內存緩存和磁盤緩存的策略,一般都會採用三級緩存策略。
對於一些網絡加載的圖片,在一些網絡差或者特殊網絡的情況下,可以出現加載慢,丟包的現象,這樣就會導致圖片一致加載失敗。慶幸的是,還有專門的圖片管理庫來來解決這個問題。那就是 react-native-fast-image。
react-native-fast-image 這個庫比較受歡迎的,它對圖片的加載和內存優化上都有着不錯的表現。這個庫在 iOS 和安卓平臺上,底層用原理也各不相同。
三 內存層面
清除資源
對於清楚資源,談不上具體的主流優化手段,確切的說,應該是一個值得關注的細節。
比如當 A 頁面中有視頻播放的模塊,而 B 頁面是 A 的二級頁面,在融合模式下,進入 A 頁面之後會開始播放視頻流,但是當從 A 頁面進入到 B 頁面之後,本質上 A 頁面並沒有被回收,但是這個時候,還在加載着視頻資源。那麼這樣下去,會讓內存越來越大。
那麼如何解決這個問題呢? 當 A 跳轉到 B 頁面之後,應該停止 A 頁面加載資源,或者清空視頻資源,讓內存維護一個健康的水平。
對於一些超多 gif 圖片的頁面,並還有列表加載功能,這樣在向下加載數據的過程中,會渲染更多的 gif 組件,這樣就會讓內存越來越大,並且不容易下來,或者一些低端的機型,根本無法渲染太多的 gif 圖片,那麼此時應該如何解決呢?
這個時候可以做一個優化,就是隻有在視圖範圍內的元素才渲染真正的 gif 圖片,而其他看不見的直接渲染圖片或者是佔位圖。如下所示:
清除狀態
對於一些全局的狀態,比如存在 Redux 中的數據源,或者是全局綁定的監聽事件,setTimeout 延時器
四 總結
本文從圖像與內存兩個方面介紹了 RN 優化手段,希望這篇文章的能給 React Native 開發同學一個性能優化上啓發。
參考
-
React Native 性能優化指南
-
大前端跨端開發指南
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/FMDx36cPxgeLkCMIneV6vg