天天看點

【老孟Flutter】如何提高Flutter應用程式的性能

在調用 setState() 方法重建元件時,一定要最小化重建元件,沒有變化的元件不要重建,看下面的Demo,這是一個設定頁面,

【老孟Flutter】如何提高Flutter應用程式的性能

注意看上圖右邊下半部分,點選切換開關的時候,所有的元件全部重建了,理想情況下,應該隻是 Switch 元件進行切換,是以将 Switch 元件進行封裝:

使用:

【老孟Flutter】如何提高Flutter應用程式的性能

此時看到重建的元件隻有 _SwitchWidget 和 Switch 元件,提高了性能。

如果 Switch 元件的狀态改變也會改變其它元件的狀态,這是典型的元件間通信,這種情況下可以使用 InheritedWidget,但更建議使用狀态管理架構(比如 Provider 等),而不是将其父元件改變為StatefulWidget。

盡量不要将整個頁面定義為 StatefulWidget 元件,因為一旦重建将重建此頁面下所有的元件,尤其是 Switch 、Radio等元件狀态的改變導緻的重建,強烈建議對其進行封裝。

這裡有一個誤區,有些人認為,将元件拆分為方法可以減少重建,就比如上面的例子,将 _SwitchWidget 元件改變為方法,該方法傳回 Switch 元件,這是錯誤的,此種方式并不能減少重建, 但是将一個元件拆分為多個小元件是可以減少重建的,就像上面的例子,将需要重建的 Switch 封裝為一個單獨的 StatefulWidget 元件,避免了其他不必要的重建。

在元件前加上 const ,相當于對此元件進行了緩存,下面是未加 const 的代碼:

【老孟Flutter】如何提高Flutter應用程式的性能

給 Text('老孟') 元件加上 const:

【老孟Flutter】如何提高Flutter應用程式的性能

對比兩次 Text 元件的重建情況,加上 const 後,未重建。

有如下場景,有一個 Text 元件有可見和不可見兩種狀态,代碼如下:

可見時的元件樹:

【老孟Flutter】如何提高Flutter應用程式的性能

不可見時的元件樹:

【老孟Flutter】如何提高Flutter應用程式的性能

兩種狀态元件樹結構發生變化,應該避免發生此種情況,優化如下:

此時不管是可見還是不可見狀态,元件樹都不會發生變化,如下:

【老孟Flutter】如何提高Flutter應用程式的性能

還有一種情況是根據不同的條件建構不同的元件,如下:

設定為 true 時的元件樹結構:

【老孟Flutter】如何提高Flutter應用程式的性能

設定為 false 時的元件樹結構:

【老孟Flutter】如何提高Flutter應用程式的性能

看到左側子節點由 RaisedButton 變為了 Text。

上面的情況元件樹發生了更改,不管是類型發生更改,還是深度發生更改,如果無法避免,那麼就将變化的元件樹封裝為一個 StatefulWidget 元件,且設定 GlobalKey,如下:

封裝變化的部分:

建構:

雖然通過 GlobalKey 提高了上面案例的性能,但我們千萬不要亂用 GlobalKey,因為管理 GlobalKey 的成本很高,是以其他需要使用 Key 的地方建議考慮使用 Key, ValueKey, ObjectKey, 和 UniqueKey。

關于 GlobalKey 的相關說明參考:https://api.flutter.dev/flutter/widgets/GlobalKey-class.html

ListView是我們最常用的元件之一,用于展示大量資料的清單。如果展示大量資料請使用 ListView.builder 或者 ListView.separated,千萬不要直接使用如下方式:

這種方式一次加載所有的元件,沒有“懶加載”,消耗極大的性能。

ListView 中 itemExtent 屬性對動态滾動到性能提升非常大,比如,有2000條資料展示,點選按鈕滾動到最後,代碼如下:

【老孟Flutter】如何提高Flutter應用程式的性能

耗時在2秒左右,加上 itemExtent 屬性,修改如下:

【老孟Flutter】如何提高Flutter應用程式的性能

優化後瞬間跳轉到底部。

這是因為不設定  itemExtent 屬性,将會由子元件自己決定大小,大量的計算導緻UI堵塞。

這裡說的是向AnimatedBuilder 、TweenAnimationBuilder 等一類的元件的問題,這些元件都有一個共同點,帶有 builder 且其參數重有 child。

以 AnimatedBuilder 為例,如果 builder 中建構的樹中包含與動畫無關的元件,将這些無關的元件當作 child 傳遞到 builder 中比直接在 builder 中建構更加有效。

比如下面的代碼,直接在 builder 中建構子元件:

優化後的代碼:

部分元件一定要謹慎使用,因為這些元件包含一些昂貴的操作,比如 saveLayer() 方法。

調用saveLayer()會配置設定一個螢幕外緩沖區。 将内容繪制到螢幕外緩沖區中可能會觸發渲染目标切換,這在較早的GPU中特别慢。

另外雖然下面這些元件比較消耗性能,但并不是禁止大家使用,而是謹慎使用,如果有替代方案,考慮使用替代方法。

尤其注意,如果這些元件頻繁重建(比如動畫的過程),要重點優化。

Clip 類元件是常用的裁剪類元件,比如:ClipOval、ClipPath、ClipRRect、ClipRect、CustomClipper。這些元件中都有 clipBehavior 屬性,不同的值性能是不同的,

越往下,速度越慢。

一些簡單的圓角元件的設定可以使用 Container 實作:

【老孟Flutter】如何提高Flutter應用程式的性能

Opacity 元件的功能是使子元件透明。此類将其子級繪制到中間緩沖區中,然後将子級混合回到部分透明的場景中。

對于除0.0和1.0之外的不透明度值,此類相對昂貴,因為它需要将子級繪制到中間緩沖區中。 對于值0.0,根本不繪制子級。 對于值1.0,将立即繪制沒有中間緩沖區的子對象。

如果僅僅是對單個 Image 或者 Color 增加透明度,直接使用比 Opacity 元件更快:

比使用 Opacity 元件更快:

如果對元件的透明度進行動畫操作,建議使用 AnimatedOpacity。

還有一些元件也要慎重使用,比如:

ShaderMask

ColorFilter

BackdropFilter