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

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

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

創造高品質的用戶體驗


使用 Widget 代替 function-widget#

  • 使用 StatefulWidget、StatelessWidget 可以在 WidgetTree 瀏覽與查詢
  • App 崩潰時在stack trace上查看

Bad#

Good#

盡量使用 const#

  • 宣告 const,避免重新繪製與造成多餘的效能消耗,讓 Flutter 僅重建應該更新的元件
  • 使用相同的 Widget 時,可以節省記憶體

使用 nil Widget 代替無意義 SizedBox 與 Container#

  • nil 為第三方套件
  • nil 元件為簡單的 Element,在創建的時候什麼都不做,擁有最小的效能影響
  • 不適用於可以包裹多個子元件的元件,例如Rows、Columns 等

nil | Flutter PackageA simple widget to add in the widget tree when you want to show nothing, with minimal impact on performance. Sometimes…pub.dev

使用狀態管理套件#

這些套件提供穩定的架構確保開發流程,更可以有效幫助資料與畫面刷新,而不是重建所有元件

flutter_riverpod | Flutter PackageA state-management library that: catches programming errors at compile time rather than at runtime removes nesting for…pub.dev

get | Flutter PackageGetX is an extra-light and powerful solution for Flutter. It combines high-performance state management, intelligent…pub.dev

flutter_bloc | Flutter PackageWidgets that make it easy to integrate blocs and cubits into Flutter. Built to work with package:bloc. Learn more at…pub.dev

避免 AnimationController 使用 setState 更新動畫#

  • 不要在 addListener() 裡使用 setState() 更新
  • 錯誤的使用方式將導致重建整個 UI,影響到其他元件,並使動畫延遲、卡頓
  • 盡量使用 AnimatedBuilder 刷新動畫

不要使用 Opacity 搭配 AnimationBuilder#

  • 改變不透明度本身是一個昂貴且耗效能的動畫
  • 實現淡入淡出,使用 FadeTransition 或 AnimatedOpacity
  • FadeTransition 不會觸發 Build 繪製UI,Build 通常會在 Layout 和 Animation 之間進行,使用 GPU 的片段著色器(fragment shader)實現漸變不透明度

Bad#

Good#

  • FadeTransition 直接透過 RenderObject 優化效能,沒有產生Element
  • Build 過程來自 Element
https://medium.com/flutter-community/flutter-laggy-animations-how-not-to-setstate-f2dd9873b8fc

or

Flutter Laggy Animations: How Not To setStateCreating animations in Flutter is really fun and easy, but there is one bad practice that might make those animations…medium.com

使用 Keys 提高效能#

  • 更好地識別 Widget
  • 提升4倍以上的效能

提醒#

  • ValueKey 讓程式碼看起來有點雜亂
  • GlobalKey 禁止濫用,看情況與作用區域決定

Elements, Keys and Flutter’s performanceTL;DR: Widget Keys can improve the performance of our application in places where you do not get the promised 60 FPS.medium.com

設置 ListView 的 itemExtent#

  • 固定列表上的子元件長度,如果是垂直滾動代表是高度; 如果是水平滾動代表是寬度
  • 有助於 Flutter 計算 ListView 的滾動位置,提前知道列表的長度,而不是創建時計算每個元件的高度(尤其是在滾動位置頻繁變化時),使性能更好

ListView 載入高像素圖片#

// 預設為true,讓每個item的狀態保持活動狀態
addAutomaticKeepAlives: true
// 預設為true,每個item都用RepainBoundry包裝,它只繪製一次以獲得更高的性能
addRepaintBoundaries: true
  • ListView 保持 item-widget 處於活動狀態,並且它不會再重新繪製
  • 在使用者操作滾動時,原本的item雖然沒有在畫面上顯示,但是一樣存在,滾動回來後直接顯示,不需要繪製消耗資源,為了確保滑動順暢

但是#

加載大量圖片(高像素圖片)後,因為沒有被釋放肯定會消耗大量內存,最終可能會使應用崩潰。可以簡單地禁用它們,這樣不可見的 item-widget 將被自動處理和被垃圾收集器回收。

提醒:將參數設置為 false,可能會導致使用更多 GPU 和 CPU 工作,因為重新繪製並管理狀態,但它可以解決記憶體問題,並且獲得高效的畫面。

Flutter Memory Optimization SeriesAlmost anything in Flutter is optimized and enhanced by default as you may already know, thanks to the Flutter teams in…medium.com

使用 for/while 代替 foreach/map#

https://itnext.io/comparing-darts-loops-which-is-the-fastest-731a03ad42a2

For loops 是最快的,先緩存迴圈長度,這是計算時間最短的寫法

for 和 while,兩種倒序方式的性能會稍差一些

Comparing Dart’s loops — which is the fastest?Dart, the language used to write Flutter apps, has many different loops which can iterate through lists or run some…itnext.io


參考#

其他文章#

關於我#

贊助#

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

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

https://www.buymeacoffee.com/yiichenhi

最後#

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

本文原刊登於 Medium。