Flutter卡頓優化錦輯

brzhang發表於2020-03-02

原文連結

Flutter卡頓優化必備基礎知識

首先,在做效能調優之前,我們應該對flutter相關基礎知識有一定的瞭解,不然我們無從做起,首先,我們要了解flutter是幹嘛的--Flutter 是谷歌2018年釋出的跨平臺移動UI框架

然後,他相對於其他跨平臺開發框架來說,是高效的,至於他為什麼高效,原因是因為:

Flutter卡頓優化錦輯

他是直接呼叫Skia框架,而其他框架需要藉助現有的原始框架來轉一下,在才開始去呼叫Skia框架,這一來二去,肯定就有所消耗,這是其一,然後,我們還需要知道flutter的四個執行緒。

四個執行緒

分別是:

平臺執行緒

該平臺的主執行緒。外掛程式碼在這裡執行。更多資訊請參閱:iOS 的程式 (UIKit) 文件,或者 Android 的主執行緒 (MainThread) 文件。效能圖層並不會展示該執行緒。

DartUI 執行緒

UI 執行緒在 Dart VM 執行 Dart 程式碼。該執行緒包括開發者寫下的程式碼和 Flutter 框架根據應用行為生成的程式碼。當應用建立和展示場景的時候,UI 執行緒首先建立一個 圖層樹(layer tree) ,一個包含裝置無關的渲染命令的輕量物件,並將圖層樹傳送到 GPU 執行緒來渲染到裝置上。不要阻塞這個執行緒!在效能圖層的最低欄展示該執行緒。

GPU 執行緒

GPU 執行緒取回圖層樹並通知 GPU 渲染。儘管無法直接與 GPU 執行緒或其資料通訊,但如果該執行緒變慢,一定是開發者 Dart 程式碼中的某處導致的。圖形庫 Skia 在該執行緒執行,有時也被叫做光柵器 (rasterizer) 執行緒。在效能圖層的最頂欄顯示該執行緒。

I/O 執行緒

可能阻塞 UI 或者 GPU 執行緒的耗時任務(大多數情況下是 I/O)。該執行緒並不會在效能圖層中展示。

所以,我們做效能優化,關心DartUI,關心GPU兩個執行緒,掉不掉幀,卡不卡的關鍵,就看這兩位了,而且在99%情況下,作為Flutter開發人員,我們我們基本上解決好,DartUI執行緒上的問題,就==解決了渲染效能問題。

三棵樹

Flutter卡頓優化錦輯
  • Widget是為Element描述需要的配置, 負責建立Element,決定Element是否需要更新。Flutter Framework通過差分演算法比對Widget樹前後的變化,決定Element的State是否改變。當重建Widget樹後並未發生改變, 則Element不會觸發重繪,則就是Widget樹的重建並不一定會觸發Element樹的重建。
  • Element表示Widget配置樹的特定位置的一個例項,同時持有Widget和RenderObject,負責管理Widget配置和RenderObject渲染。Element狀態由Flutter Framework管理, 開發人員只需更改Widget即可。
  • RenderObject表示渲染樹的一個物件,負責真正的渲染工作,比如測量大小、位置、繪製等都由RenderObject完成。

為了更加直觀的表示3個樹的從生到死,我不得不丟擲下面這幅圖來

Flutter卡頓優化錦輯

然後,我們經常在做效能調優的時候,會用到timeline工具,你會看到這樣一幅圖:

Flutter卡頓優化錦輯

現在串起來了嗎,4個執行緒build---layout---paint三個階段是不是都一目瞭然,各發生在什麼地方,什麼階段,誰先誰後。

所以,我們說 要解決卡頓掉幀的問題,就是要解決build,layout,paint這三個階段各函式執行耗時的問題。

具體如何做效能優化

首先,我們配置下環境,這裡我配置這個變數debugProfileBuildsEnabled=true不然,我不知道build他具體做了些啥,觀望臺預設不會告訴我。一般來說,放在main函式中,在runApp之前開啟即可,比如我是這麼幹的:

Flutter卡頓優化錦輯

這裡面有一些其他需要用到的開關,可以在資料不足的時候開啟,這樣我們參考的資料多些,優化的參考點就明確些。

然後,我們執行 flutter run --profile ,請記住,我們需要在profile模式來效能調優,debug模式因為在渲染過程中記錄了很多分析資料且加上支援熱過載的特性是損失了很多效能為代價的,profile模式更加接近release模式效能。

然後跑起來了,會出現一個連結:

Flutter卡頓優化錦輯

點一下就去了觀望臺了,當然,你也可以使用devTools,貌似後面會取代觀望臺。devTools的啟動姿勢是:

flutter pub global activate devtools
devTools複製程式碼

先安裝,然後在直接執行即可:

Flutter卡頓優化錦輯

點選這個連結,會彈出一個網頁來,讓你輸入url,這個url就是我們那個觀望臺的url,因此你似乎秒懂了,然來,devTools是在觀望臺的基礎至上做的一個分析工具,所以,Google一定是覺得觀望臺不大友好了,然而,遺憾的是,devTools並不是特別全面,因為現在還是preview階段嘛,一切都會好起來的。

好的,假如,我們的app有效能問題,我們就會開啟觀望臺,然後開啟timeLine,點選Flutter Develop,然後在你覺得有問題的頁面多操作記下,然後點選右上角Refresh按鈕,就會出現:

Flutter卡頓優化錦輯

通常來說,很容易發現有問題的地方,明顯那個會比較寬比較長的地方就比較可以,這種一遍就可以定位頁面載入比較慢了,然後我們點選向下箭頭,把他放大點看看

Flutter卡頓優化錦輯

大概就看到了,偶,然後,我們點選選擇,在選擇一個範圍看看統計效果:

Flutter卡頓優化錦輯

這時候,我們就發現問題了,然後這個也載入了這麼多個TipCacheNetWorkImage,然後每個大概要2ms,然後我這個是一個列表頁:

Flutter卡頓優化錦輯

所以,一共就有8個這樣的控制元件要渲染,而他,就佔用8 *2.188 > 16ms,因此我們找到了優化點,解決這個就可以加速渲染了,這裡只是舉例找到存在效能瓶頸的地方,具體相關函式耗時的優化,相信大家都懂的,這就是演算法相關的問題了。

然後就是幾點程式碼建議

1、儘量將setState放在葉子節點,好處是build時影響範圍極小,簡稱區域性重新整理

Flutter卡頓優化錦輯

2、能不用 Opacity Widget,就儘量不要用,因為這貨會粗發GPU一個saveLayer的指令,做Skia的大神說,這個指令相當耗時。

3、使用ListView.builder()而不是直接使用ListView()來構建列表。

4、對於頻繁更新的控制元件(比如倒數計時,秒錶),使用RepaintBoundary隔離它,讓他在一個獨立的paint區域。

5、使用const來修飾永遠不需要變更的控制元件。

6、優先使用StateLessWidget,而不是全部用StateFulWidget

7、使用Visibility控制元件替換if/else,有些小夥伴喜歡else時return一個 佔位控制元件,須不知,這種效率是沒有Visibility高效的。

參考資料

除錯 Flutter 應用 - Flutter 中文文件 - Flutter 社群中文資源

zhuanlan.zhihu.com/p/88478737

files.flutter-io.cn/events/gdd2…

Flutter 應用效能優化最佳實踐 - Flutter 中文文件 - Flutter 社群中文資源

mrale.ph/dartvm/

medium.com/flutter/man…


相關文章