yii.
← Writing
Flutter 技術 · · 5 min read

提高Flutter性能的小技巧!(二)

這篇寫於 2022 年。工具和 API 變化很快,部分步驟可能已經不適用。

創造高品質的用戶體驗


繁重、複雜的任務請使用 Isolates#

大量的文字與圖像運算可能會堵塞主線程,適當使用 Isolate 可以提升性能並優化使用者體驗。

我的另一篇文章有說明 Isolates,以及用它實作了一些範例,請查看

What are Async and Isolates in Flutter?創造高品質的用戶體驗yii · writing

使用 RepaintBoundary 重繪邊界#

  1. 當只有一小部分元件需要刷新,而其他UI部分是靜態且固定的,這個情況很適合使用 RepaintBoundary 包裹不需要更新的元件
  2. 緩存並防止不必要的繪製,有需要才動作,不會因其他狀態的刷新或改變而影響,提高性能
  3. 創建一個獨立的 display list(一連串輸出圖像的命令) 包含許多元件,可以將主要渲染元件與其他元件分割,不同 Layer 的分離,實現只繪製內容發生變化的 subtree
  4. 告訴 Flutter 這些元件應該在不同的 WidgetTree,處理自己的繪製,不會被其他不相關的繪製影響
  5. 有助於限制 markNeedsPaint 在渲染樹上的使用和 paintChild 的使用,避免同一層的相關 RenderObject 被重新繪製。通常只要child.isRepaintBoundary 為 false,那麼就會執行 paint 方法,重新繪製子元件
  6. ListView 預設使用了 RepaintBoundary,當滾動列表的時候 item-widget 會保留且不再重新繪製

注意:濫用可能會造成過多的記憶體使用,因為需要緩存更多資訊

Flutter 繪製#

如果 RenderObject 被設為 dirty,代表繪製動作被觸發,Flutter 會對 Layer 中的其他相關 RenderObject 進行重新繪製,對所有祖先做一樣的事情,直到源頭 RenderObject

另外#

在 main 可以設置 debugRepaintRainbowEnabled 為 true,畫面會將元件透過顏色線條框起來,可幫助發現被繪製的區塊,有刷新的線條顏色會一直變換

RepaintBoundary In FlutterLearn How To Use RepaintBoundary In Your Flutter Appsmedium.flutterdevs.com

盡量使用 builder 建構子#

  • builder 只渲染顯示在畫面上的元件
  • ListView → ListView.builder
  • InteractiveViewer → InteractiveViewer.builder ,強力的客製化清單元件,滾動方向與內容渲染自行定義,最佳化性能

不要對滾動元件使用 ShrinkWrap#

會花費許多性能在計算元件。

預先載入圖片或 Icon#

SVG Image ➤ flutter_svg

添加圖片載入效果#

  • 提升使用者體驗
  • 使用圖像的 Hash 字串顯示模糊預覽

將檔案轉成 HashEncode#

可以將圖片跟 Hash 字串儲存到雲端,等待下次載入使用。

實際使用#

搭配套件 octo_image。

flutter_blurhash | Flutter PackageCompact representation of a placeholder for an image. You can use https://blurha.sh/ for testing or use any official…pub.dev

幫圖片設置緩存寬高#

加載高解析度的圖像時,通常會導致卡頓,因為將原始圖像壓縮到所需的螢幕顯示尺寸,這個任務很繁重。因此,最好提供 maxWidth、maxHeight 以在讀取時自動調整圖像大小。

  • 減少記憶體的使用
  • 避免卡頓
  • 減少圖像的體積
  • 加載的時間更短
  • 渲染圖像時提高了性能

使用 AspectRatio 顯示圖片#

  • 縱橫比,長度與寬度的比率
  • 顯示長200寬150的圖像,縱橫比為 1.33 (200/150)
  • 在所有設備上保持圖像的一致性,即使設備的解析度不同,它也會自動放大或縮小圖像以符合 UI

根據條件顯示不同的元件#

以下為聊天室範例

  • 假設將來 APP 有更新,將添加一個 messageType 為 pdfFile,那麼對於使用舊版本的用戶,APP 可能會崩潰,因為對他們來說,這個 pdfFile 類型的新訊息也會返回 ImageWidget
  • 可以改成在 else 條件裡返回對版本無影響的元件,不需要擔心適配問題

適時 dispose() 釋放資源#

  1. 避免記憶體洩漏,影響性能
  2. 官方說明,super.dispose() 應該作為 Widget-dispose 的最後一個執行函式,資源釋放需要在之前執行,如果在後面則不會處理

補充:initState()裡,super.initState 應該為第一個執行函式


參考#

其他文章#

關於我#

贊助#

謝謝你!這是一個很長的文章而且你花費時間看完,真的非常感謝。

還有一件事, 如果覺得文章不錯可以贊助我,讓我有更多的動力和熱情分享 學習筆記和生活!請我喝一杯咖啡吧~

https://www.buymeacoffee.com/yiichenhi

最後#

希望有幫助到你/妳,歡迎追蹤我,方便瀏覽最新的文章,也請別忘記給我拍手哦 (最多可以達到50次)!

本文原刊登於 Medium。