??Flutter 性能優(yōu)化實(shí)踐 總結(jié)??

在flutter的開(kāi)發(fā)和工作中眨唬,因?yàn)楣ぷ鲀?nèi)容的要求越來(lái)越高,加上一位優(yōu)秀的同事姥闪,自己也對(duì)自己的寫(xiě)的代碼除了規(guī)范的要求,也開(kāi)始對(duì)性能做了優(yōu)化砌烁。我們開(kāi)發(fā)的App屬于首頁(yè)就是重點(diǎn)甘畅,剛好是我負(fù)責(zé),所以再簡(jiǎn)單的UI和邏輯搭建完成后往弓,要求達(dá)到一定的性能優(yōu)化疏唾,所以自己開(kāi)始了解和學(xué)習(xí)相關(guān)的處理。

摘自:https://juejin.im/post/5dfc64526fb9a01601169c28#heading-14

0.渲染相關(guān)知識(shí)了解

0.0 Flutter有四種運(yùn)行模式:Debug函似、Release槐脏、Profile和test,這四種模式在build的時(shí)候是完全獨(dú)立的撇寞。

Debug
??Debug模式可以在真機(jī)和模擬器上同時(shí)運(yùn)行:會(huì)打開(kāi)所有的斷言顿天,包括debugging信息堂氯、debugger aids(比如observatory)和服務(wù)擴(kuò)展。優(yōu)化了快速develop/run循環(huán)牌废,但是沒(méi)有優(yōu)化執(zhí)行速度咽白、二進(jìn)制大小和部署。命令flutter run就是以這種模式運(yùn)行的鸟缕,通過(guò)sky/tools/gn --android或者sky/tools/gn --ios來(lái)build晶框。有時(shí)候也被叫做“checked模式”或者“slow模式”。

Release
??Release模式只能在真機(jī)上運(yùn)行懂从,不能在模擬器上運(yùn)行:會(huì)關(guān)閉所有斷言和debugging信息授段,關(guān)閉所有debugger工具。優(yōu)化了快速啟動(dòng)番甩、快速執(zhí)行和減小包體積侵贵。禁用所有的debugging aids和服務(wù)擴(kuò)展。這個(gè)模式是為了部署給最終的用戶使用缘薛。命令flutter run --release就是以這種模式運(yùn)行的窍育,通過(guò)sky/tools/gn --android --runtime-mode=release或者sky/tools/gn --ios --runtime-mode=release來(lái)build。

Profile
?? Profile模式只能在真機(jī)上運(yùn)行,不能在模擬器上運(yùn)行:基本和Release模式一致,除了啟用了服務(wù)擴(kuò)展和tracing魁巩,以及一些為了最低限度支持tracing運(yùn)行的東西(比如可以連接observatory到進(jìn)程)。命令flutter run --profile就是以這種模式運(yùn)行的,通過(guò)sky/tools/gn --android --runtime-mode=profile或者sky/tools/gn --ios --runtime-mode=profile```來(lái)build浩嫌。因?yàn)槟M器不能代表真實(shí)場(chǎng)景檐迟,所以不能在模擬器上運(yùn)行。

test
?? headless test模式只能在桌面上運(yùn)行:基本和Debug模式一致码耐,除了是headless的而且你能在桌面運(yùn)行追迟。命令flutter test就是以這種模式運(yùn)行的,通過(guò)sky/tools/gn來(lái)build骚腥。

0.1 Flutter的架構(gòu)主要分成三層:Framework敦间,Engine,Embedder束铭。

1.Framework使用dart實(shí)現(xiàn)廓块,包括Material 
Design風(fēng)格的Widget,Cupertino(針對(duì)iOS)風(fēng)格的Widgets,文本/圖片/按鈕等基礎(chǔ)Widgets契沫,渲染带猴,動(dòng)畫(huà),手勢(shì)等懈万。
此部分的核心代碼是:flutter倉(cāng)庫(kù)下的flutter 
package拴清,以及sky_engine倉(cāng)庫(kù)下的io,async,ui(dart:ui庫(kù)提供了Flutter框架和引擎之間的接口)等package靶病。

2.Engine使用C++實(shí)現(xiàn),主要包括:Skia,Dart和Text口予。
Skia是開(kāi)源的二維圖形庫(kù)娄周,提供了適用于多種軟硬件平臺(tái)的通用API。

3.Embedder是一個(gè)嵌入層沪停,即把Flutter嵌入到各個(gè)平臺(tái)上去煤辨,這里做的主要工作包括渲染Surface設(shè)置,線程設(shè)置,以及插件等牙甫。
從這里可以看出掷酗,F(xiàn)lutter的平臺(tái)相關(guān)層很低,平臺(tái)(如iOS)只是提供一個(gè)畫(huà)布窟哺,剩余的所有渲染相關(guān)的邏輯都在Flutter內(nèi)部泻轰,這就使得它具有了很好的跨端一致性。

0.2 Widget且轨、Element浮声、RenderObject三者的關(guān)系如下:

Widget實(shí)際上就是Element的配置數(shù)據(jù),Widget樹(shù)實(shí)際上是一個(gè)配置樹(shù)旋奢,而真正的UI渲染樹(shù)是由Element構(gòu)成泳挥;不過(guò),由于Element是通過(guò)Widget生成至朗,所以它們之間有對(duì)應(yīng)關(guān)系屉符,所以在大多數(shù)場(chǎng)景,我們可以寬泛地認(rèn)為Widget樹(shù)就是指UI控件樹(shù)或UI渲染樹(shù)锹引。

一個(gè)Widget對(duì)象可以對(duì)應(yīng)多個(gè)Element對(duì)象矗钟。這很好理解,根據(jù)同一份配置(Widget)嫌变,可以創(chuàng)建多個(gè)實(shí)例(Element)吨艇。

從創(chuàng)建到渲染的大體流程是:根據(jù)Widget生成Element,然后創(chuàng)建相應(yīng)的RenderObject并關(guān)聯(lián)到Element.renderObject屬性上腾啥,最后再通過(guò)RenderObject來(lái)完成布局排列和繪制东涡。

1.能否在模擬器下進(jìn)行性能調(diào)試?

答案:可以倘待,但是調(diào)試很不準(zhǔn)確疮跑。所以不建議使用模擬器進(jìn)行性能調(diào)試。
幾乎全部的 Flutter 應(yīng)用性能調(diào)試都應(yīng)該在真實(shí)的 Android 或者 iOS 設(shè)備上以分析模式進(jìn)行凸舵。
通常來(lái)說(shuō)祸挪,調(diào)試模式或者是模擬器上運(yùn)行的應(yīng)用的性能指標(biāo)和發(fā)布模式的表現(xiàn)并不相同。 
應(yīng)該考慮在用戶使用的最慢的設(shè)備上檢查性能贞间。

另附收集的大廠面試題贿条,進(jìn)群可自行下載雹仿!


  • 為什么應(yīng)該在真機(jī)上運(yùn)行:

    • 各種模擬器使用的硬件并不相同暇仲,因此性能也不同—模擬器上的一些操作會(huì)比真機(jī)快,而另一些操作則會(huì)比真機(jī)慢副渴。

    • 調(diào)試模式相比分析模式或者發(fā)布編譯來(lái)說(shuō)奈附,增加了額外的檢查(例如斷言),這些檢查可能相當(dāng)耗費(fèi)資源煮剧。

  • 調(diào)試模式和發(fā)布模式代碼執(zhí)行的方式也是不同的斥滤。調(diào)試編譯采用的是“just in time”(JIT)模式運(yùn)行應(yīng)用,而分析和發(fā)布模式則是預(yù)編譯到本地指令(“ahead of time”勉盅,或者叫 AOT)之后再加載到設(shè)備中佑颇。JIT本身的編譯就可能導(dǎo)致應(yīng)用暫停,從而導(dǎo)致卡頓菇篡。


2.如何進(jìn)行App性能測(cè)試?

答案:
1.在 Android Studio 和 IntelliJ 使用 Run > Flutter Run main.dart in Profile Mode 選項(xiàng)
    1.1 選擇 View > Tool Windows > Flutter Inspector一喘。
    1.2 在工具欄中選擇書(shū)架圖標(biāo)驱还。

2.在 VS Code中,打開(kāi) launch.json 文件凸克,設(shè)置 flutterMode 屬性為 profile(當(dāng)分析完成后议蟆,改回 release 或者 debug)
    2.1 選擇 View > Command Palette… 來(lái)打開(kāi) command palette。
    2.2 在文本框中輸入“performance”并在彈出列表中選中 Toggle Performance Overlay萎战。如果命令不可用咐容,請(qǐng)確保應(yīng)用在運(yùn)行狀態(tài)。

3.From the command line, use the --profile flag: 命令行使用 --profile 參數(shù)運(yùn)行
  3.1 flutter run --profile
  3.2 使用 p 參數(shù)觸發(fā)性能圖層

4.可以通過(guò)在 MaterialApp 或者 WidgetsApp 的構(gòu)造方法中設(shè)置 showPerformanceOverlay 屬性為 true 來(lái)展示 PerformanceOverlay widget:
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      showPerformanceOverlay: true,
      title: 'My Awesome App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'My Awesome App'),
    );
  }
}
復(fù)制代碼

3.如何查看分析性能圖層蚂维?

答案:
性能圖層用兩張圖表顯示應(yīng)用的耗時(shí)信息戳粒。如果 UI 產(chǎn)生了卡頓(跳幀)路狮,這些圖表可以幫助分析原因。圖表在當(dāng)前應(yīng)用的最上層展示蔚约,但并不是用普通的 widget 方式繪制的—Flutter 引擎自身繪制了該圖層來(lái)盡可能減少對(duì)性能的影響奄妨。每一張圖表都代表當(dāng)前線程的最近 300 幀表現(xiàn)。

左圖:GPU 線程的性能情況在上面苹祟,UI 線程顯示在下面砸抛,垂直的綠色條條代表的是當(dāng)前幀。
右圖:每一幀渲染過(guò)程當(dāng)中總共使用的時(shí)間
復(fù)制代碼
Flutter 用了一些額外的線程來(lái)完成這項(xiàng)工作树枫。開(kāi)發(fā)者的 Dart 代碼都在 UI 線程運(yùn)行直焙。盡管沒(méi)有直接訪問(wèn)其他線程的權(quán)限,但 UI 線程的動(dòng)作還是對(duì)其他線程的性能有影響的砂轻。

平臺(tái)線程
該平臺(tái)的主線程奔誓。插件代碼在這里運(yùn)行。更多信息請(qǐng)參閱:iOS 的 UIKit 文檔舔清,或者 Android 的 MainThread 文檔丝里。性能圖層并不會(huì)展示該線程。

UI 線程
UI 線程在 Dart VM 執(zhí)行 Dart 代碼体谒。該線程包括開(kāi)發(fā)者寫(xiě)下的代碼和 Flutter 框架根據(jù)應(yīng)用行為生成的代碼杯聚。當(dāng)應(yīng)用創(chuàng)建和展示場(chǎng)景的時(shí)候,UI 線程首先建立一個(gè) 圖層樹(shù)(layer tree) 抒痒,一個(gè)包含設(shè)備無(wú)關(guān)的渲染命令的輕量對(duì)象幌绍,并將圖層樹(shù)發(fā)送到 GPU 線程來(lái)渲染到設(shè)備上。 不要阻塞這個(gè)線程故响! 在性能圖層的最低欄展示該線程傀广。

GPU 線程
GPU 線程取回圖層樹(shù)并通知 GPU 渲染。盡管無(wú)法直接與 GPU 線程或其數(shù)據(jù)通信彩届,但如果該線程變慢伪冰,一定是開(kāi)發(fā)者 Dart 代碼中的某處導(dǎo)致的。圖形庫(kù) Skia 在該線程運(yùn)行樟蠕,有時(shí)也被叫做 光柵器(rasterizer)線程 贮聂。在性能圖層的最頂欄展示該線程。

I/O 線程
可能阻塞 UI 或者 GPU 線程的耗時(shí)任務(wù)(大多數(shù)情況下是I/O)寨辩。該線程并不會(huì)在性能圖層中展示吓懈。
復(fù)制代碼

紅色豎條表明當(dāng)前幀的渲染和繪制都很耗時(shí) 當(dāng)兩張圖表都是紅色時(shí),就要開(kāi)始對(duì) UI 線程(Dart VM)進(jìn)行診斷了靡狞。

每一幀都應(yīng)該在 1/60 秒(大約 16ms)內(nèi)創(chuàng)建并顯示耻警。
如果有一幀超時(shí)(任意圖像)而無(wú)法顯示,就導(dǎo)致了卡頓,圖表之一就會(huì)展示出來(lái)一個(gè)紅色豎條甘穿。
如果是在 UI 圖表出現(xiàn)了紅色豎條腮恩,則表明 Dart 代碼消耗了大量資源。
而如果紅色豎條是在 GPU 圖表出現(xiàn)的扒磁,意味著場(chǎng)景太復(fù)雜導(dǎo)致無(wú)法快速渲染庆揪。
復(fù)制代碼
為什么需要在 16ms 內(nèi)渲染完成每一幀
1.將幀渲染時(shí)間降低到 16ms 以下可能在視覺(jué)上看不出來(lái)什么變化,但可以延長(zhǎng)電池壽命以及避免發(fā)熱問(wèn)題妨托。
2.可能在你當(dāng)前測(cè)試設(shè)備上運(yùn)行良好缸榛,但請(qǐng)考慮在應(yīng)用所支持的最低端設(shè)備上的情況。
3.當(dāng) 120fps 的設(shè)備普及之后兰伤,便需要在 8ms 之內(nèi)完成每一幀的渲染來(lái)保證流暢平滑的體驗(yàn)内颗。
復(fù)制代碼

4.如何進(jìn)行性能分析并開(kāi)始處理?

4.1 定位 UI 圖表中的問(wèn)題

如果性能圖層的 UI 圖表顯示紅色敦腔,就要從分析 Dart VM 開(kāi)始著手了均澳,即使 GPU 圖表同樣顯示紅色。

使用 Dart DevTool 進(jìn)行性能分析
Dart DevTool 提供諸如性能分析符衔、堆測(cè)試以及顯示代碼覆蓋率等功能找前。
DevTool 的 timeline 界面可以讓開(kāi)發(fā)者逐幀分析應(yīng)用的 UI 性能。
復(fù)制代碼

(Observatory 被 Dart DevTools 取代了判族。這個(gè)基于瀏覽器的工具仍在開(kāi)發(fā)中躺盛,但只用來(lái)預(yù)覽。參考 DevTools’ docs 頁(yè)面來(lái)獲取安裝和使用指導(dǎo)形帮。)

4.2 定位 GPU 圖表中的問(wèn)題

有些情況下界面的圖層樹(shù)構(gòu)造起來(lái)雖然容易槽惫,但在 GPU 線程下渲染卻很耗時(shí)。
這種情況發(fā)生時(shí)辩撑,UI 圖表沒(méi)有紅色界斜,但 GPU 圖表會(huì)顯示紅色。
這時(shí)需要找出代碼中導(dǎo)致渲染緩慢的原因合冀。
特定類型的負(fù)載對(duì) GPU 來(lái)說(shuō)會(huì)更加復(fù)雜各薇。
可能包括不必要的對(duì) saveLayer 的調(diào)用,許多對(duì)象間的復(fù)雜操作君躺,還可能是特定情形下的裁剪或者陰影峭判。
復(fù)制代碼

如果推斷的原因是動(dòng)畫(huà)中的卡頓的話,可以使用 timeDilation 屬性來(lái)極大地放慢動(dòng)畫(huà)晰洒。也可以使用 Flutter Inspector 來(lái)減慢動(dòng)畫(huà)速度朝抖。在 inspector 的 gear 菜單下選中 Enable Slow Animations啥箭。如果想對(duì)動(dòng)畫(huà)速度進(jìn)行更多操作谍珊,請(qǐng)?jiān)诖a中設(shè)置 timeDilation 屬性。卡頓是第一幀發(fā)生的還是貫穿整個(gè)動(dòng)畫(huà)過(guò)程呢砌滞?如果是整個(gè)動(dòng)畫(huà)過(guò)程的話侮邀,會(huì)是裁剪導(dǎo)致的么?也許有可以替代裁剪的方法來(lái)繪制場(chǎng)景贝润。比如說(shuō)绊茧,不透明圖層的長(zhǎng)方形中用尖角來(lái)取代圓角裁剪。如果是一個(gè)靜態(tài)場(chǎng)景的淡入打掘、旋轉(zhuǎn)或者其他操作华畏,可以嘗試使用 RepaintBoundary。

4.2.1 檢查屏幕之外的視圖

saveLayer

saveLayer 方法是 Flutter 框架中最重量的操作之一尊蚁。 更新屏幕時(shí)這個(gè)方法很有用亡笑,但它可能使應(yīng)用變慢,如果不是必須的話横朋,應(yīng)該避免使用這個(gè)方法仑乌。 即便沒(méi)有顯式地調(diào)用 saveLayer,也可能在其他操作中間接調(diào)用了該方法琴锭∥酰可以使用 PerformanceOverlayLayer.checkerboardOffscreenLayers 開(kāi)關(guān)來(lái)檢查場(chǎng)景是否使用了 saveLayer。 打開(kāi)開(kāi)關(guān)之后决帖,運(yùn)行應(yīng)用并檢查是否有圖像的輪廓閃爍厕九。如果有新的幀渲染的話,容器就會(huì)閃爍古瓤。 舉個(gè)例子止剖,也許有一組對(duì)象的透明度要使用 saveLayer 來(lái)渲染。 在這種情況下落君,相比通過(guò) widget 樹(shù)中高層次的父 widget 操作穿香,單獨(dú)對(duì)每個(gè) widget 來(lái)應(yīng)用透明度可能性能會(huì)更好。其他可能大量消耗資源的操作也同理绎速,比如裁剪或者陰影皮获。

透明度(Opacity)、裁剪(clipping)以及陰影(shadows)它們本身并不是個(gè)糟糕的注意纹冤。然而對(duì) widget 樹(shù)頂層 widget 的操作可能導(dǎo)致額外對(duì) saveLayer 的調(diào)用以及無(wú)用的處理洒宝。

4.2.2 檢查沒(méi)有緩存的圖像

RepaintBoundary 使用 RepaintBoundary 來(lái)緩存圖片是個(gè)好主意, 當(dāng)需要的時(shí)候 萌京。 從資源的角度看雁歌,最重量級(jí)的操作之一是用圖像文件來(lái)渲染紋理。 首先知残,需要從持久存儲(chǔ)中取出壓縮圖像靠瞎,然后解壓縮到宿主存儲(chǔ)中(GPU 存儲(chǔ)),再傳輸?shù)皆O(shè)備存儲(chǔ)器中(RAM)。也就是說(shuō)乏盐,圖像的 I/O 操作是重量級(jí)的佳窑。 緩存提供了復(fù)雜層次的快照,這樣就可以方便地渲染到隨后的幀中父能。 因?yàn)楣鈻啪彺嫒肟诘臉?gòu)建需要大量資源神凑,同時(shí)增加了 GPU 存儲(chǔ)的負(fù)載,所以只在必須時(shí)才緩存圖片何吝。 打開(kāi)PerformanceOverlayLayer.checkerboardRasterCacheImages 開(kāi)關(guān)可以檢查哪些圖片被緩存了溉委。 運(yùn)行應(yīng)用來(lái)查看使用隨機(jī)顏色網(wǎng)格渲染的圖像,標(biāo)識(shí)被緩存的圖像爱榕。當(dāng)和場(chǎng)景交互時(shí)薛躬,網(wǎng)格里的圖片應(yīng)該是靜止的—代表重新緩存圖片的閃爍視圖不應(yīng)該出現(xiàn)。 大多數(shù)情況下呆细,開(kāi)發(fā)者都希望在網(wǎng)格里看到的是靜態(tài)圖片型宝,而不是非靜態(tài)圖片。如果靜態(tài)圖片沒(méi)有被緩存絮爷,可以將其放到 RepaintBoundary widget 中來(lái)緩存趴酣。雖然引擎也可能忽略 repaint boundary,如果它認(rèn)為圖像還不夠復(fù)雜的話坑夯。

4.2.3 檢視 widget 重建性能

顯示性能數(shù)據(jù) Flutter 框架的設(shè)計(jì)使得構(gòu)建達(dá)不到 60fps 流暢度的應(yīng)用變得困難岖寞。通常情況下如果卡頓,就是因?yàn)槊恳粠恢亟ǖ?UI 比需求更多的簡(jiǎn)單 bug柜蜈。Widget rebuild profiler 可以幫助調(diào)試和修復(fù)這些問(wèn)題引起的 bug仗谆。 可以檢視 widget inspector 中當(dāng)前屏幕和幀下的 widget 重建數(shù)量。了解細(xì)節(jié)淑履,可以參考 在 Android Studio 或類 IntelliJ 里開(kāi)發(fā) Flutter 應(yīng)用 中的 顯示性能數(shù)據(jù)隶垮。

5.UI 應(yīng)用性能優(yōu)化總結(jié)

5.1 UI 渲染










5.2 UI 調(diào)試步驟

1.在mian里面設(shè)置

  • debugDumpLayerTree ○ 查看layer樹(shù)
  • debugPaintLayerBordersEnabled ○ 查看layer界限
  • debugRepaintRainbowEnabled ○ 被重新繪制的RenderObject
  • debugProfilePaintsEnabled ○ 在觀測(cè)臺(tái)里顯示繪制樹(shù)

2.profile下真機(jī)運(yùn)行

3.選擇Open TimeLine View,建議使用chrome打開(kāi)

4.查看分析

image.png

5.3 UI 提高性能的總結(jié)

1.避免在 build() 方法中進(jìn)行重復(fù)且耗時(shí)的工作秘噪,因?yàn)楫?dāng)父 Widget 重建時(shí)狸吞,子 Wdiget 的 build() 方法會(huì)被頻繁地調(diào)用。

2.當(dāng)在 State 上調(diào)用 setState()時(shí)指煎,所有后代 Widget 都將重建蹋偏。因此,將 setState() 的調(diào)用轉(zhuǎn)移到其 UI 實(shí)際需要更改的 Widget 子樹(shù)部分至壤。如果改變的部分僅包含在 Widget 樹(shù)的一小部分中威始,請(qǐng)避免在 Widget 樹(shù)的更高層級(jí)中調(diào)用 setState()∠窠郑【提高build的效率- 降低遍歷的出發(fā)點(diǎn)】

3.當(dāng)重新遇到與前一幀相同的子 Widget 實(shí)例時(shí)黎棠,將停止遍歷京郑。這種技術(shù)在框架內(nèi)部大量使用,用于優(yōu)化動(dòng)畫(huà)不影響子樹(shù)的動(dòng)畫(huà)葫掉。請(qǐng)參閱 TransitionBuilder 模式和使用此原則的 SlideTransition,以避免在動(dòng)畫(huà)過(guò)程中重建其后代 Widget跟狱〖蠛瘢【提高build的效率- 停止樹(shù)的遍歷】

4.需要更新的地方添加RepaintBoundary去設(shè)置一個(gè)獨(dú)立圖層,來(lái)減少圖層更新節(jié)點(diǎn)的數(shù)量【提高paint的效率】

6.GPU 應(yīng)用性能優(yōu)化總結(jié)

6.1 GPU 圖形渲染

因?yàn)镈art代碼直接調(diào)用SKia的C和C++代碼驶臊,當(dāng)Dart代碼能夠媲美Java代碼就能夠達(dá)到Flutter App的性能媲美原生App挪挤。

Skia(開(kāi)源圖形引擎)是一個(gè)C++的開(kāi)源2D向量圖形處理函數(shù)庫(kù)(Cairo是一個(gè)矢量庫(kù)),包括字型关翎、坐標(biāo)轉(zhuǎn)換扛门、位圖等等,相當(dāng)于輕量級(jí)的Cairo纵寝,目前主要用于Google的Android和Chrome平臺(tái)论寨,Skia搭配OpenGL/ES與特定的硬件特征,強(qiáng)化顯示的效果爽茴。另外葬凳,Skia是WebKit支持的眾多圖形平臺(tái)之一,在WebKit的GraphicsContext.h/.c中有相關(guān)實(shí)現(xiàn)室奏。

6.2 GPU 調(diào)試步驟

使用真機(jī)進(jìn)行性能調(diào)試火焰,Skia 有兩套很不同的后端,F(xiàn)lutter在iOS模擬器中使用純CPU后端胧沫,而真機(jī)設(shè)備一般使用GPU硬件加速后端昌简,所以性能特性很不一樣

1.在項(xiàng)目路徑下運(yùn)行:flutter run --profile --trace-skia

2.點(diǎn)擊運(yùn)行完成后的鏈接,打開(kāi)的其實(shí)就是TimeLine View绒怨,但這時(shí)候需要選擇All纯赎,把所有函數(shù)都勾選上

3.然后操作App,點(diǎn)擊refresh生成渲染圖表南蹂。

4.flutter 將一幀錄制成SkPicture(skp)送給Skia進(jìn)行渲染址否。
用flutter screenshot --type=skia --observatory-port=<port>捕捉skp,并利用[debugger.skia.org]()我們可以上傳skp然后單步分析每一條繪圖指令碎紊。
復(fù)制代碼

6.3 GPU 提高性能的總結(jié)

1.避免使用 Opacity widget佑附,尤其是在動(dòng)畫(huà)中避免使用。請(qǐng)用 AnimatedOpacity 或 FadeInImage 進(jìn)行代替仗考。更多信息音同,請(qǐng)參閱:Performance considerations for opacity animation

有關(guān)將透明度直接應(yīng)用于圖像的示例,請(qǐng)參見(jiàn) Transparent image秃嗜,這比使用 Opacity widget 更快权均。
  For example:
  Container(color: Color.fromRGBO(255, 0, 0, 0.5))  ??
  Opacity(opacity: 0.5, child: Container(color: Colors.red)). ??
復(fù)制代碼

2.Clip 不會(huì)調(diào)用 saveLayer()(除非明確使用 Clip.antiAliasWithSaveLayer)顿膨,因此這些操作沒(méi)有 Opacity 那么耗時(shí),但仍然很耗時(shí)叽赊,所以請(qǐng)謹(jǐn)慎使用恋沃。

3.如果大多數(shù) children widget 在屏幕上不可見(jiàn),請(qǐng)避免使用返回具體列表的構(gòu)造函數(shù)(例如 Column() 或 ListView())必指,以避免構(gòu)建成本囊咏。使用帶有回調(diào)的惰性方法(例如ListView.builder)。

4.避免調(diào)用 saveLayer()塔橡。

【為什么 saveLayer 代價(jià)很大梅割?】
調(diào)用 saveLayer() 會(huì)開(kāi)辟一片離屏緩沖區(qū)。將內(nèi)容繪制到離屏緩沖區(qū)可能會(huì)觸發(fā)渲染目標(biāo)切換葛家,這些切換在較早期的 GPU 中特別慢户辞。

下面可能觸發(fā)saveLayer
  1  ShaderMask
  2  ColorFilter
  3  Chip -- might cause call to saveLayer() if disabledColorAlpha != 0xff
  4 Text -- might cause call to saveLayer() if there’s an overflowShader 

 避免調(diào)用 saveLayer() 的方式: 
  1: 要在圖像中實(shí)現(xiàn)淡入淡出,請(qǐng)考慮使用 FadeInImage 小部件癞谒,該小部件使用 GPU 的片段著色器應(yīng)用漸變不透明度底燎。了解更多詳情,請(qǐng)參見(jiàn) Opacity 文檔弹砚。
  2: 要?jiǎng)?chuàng)建帶圓角的矩形书蚪,而不是應(yīng)用剪切矩形,請(qǐng)考慮使用很多 widget 都提供的 borderRadius屬性迅栅。
復(fù)制代碼

5.當(dāng)有些widget被遮擋住了殊校,不需要渲染了,可以使用Visibility來(lái)控制不可見(jiàn)读存。

6.使用 AnimatedBuilder 時(shí)为流,請(qǐng)避免在不依賴于動(dòng)畫(huà)的 widget 的構(gòu)造方法中構(gòu)建 widget 樹(shù)。動(dòng)畫(huà)的每次變動(dòng)都會(huì)重建這個(gè) widget 樹(shù)让簿。而應(yīng)該構(gòu)建子樹(shù)的那一部分敬察,并將其作為 child 傳遞給 AnimatedBuilder。

7.避免在動(dòng)畫(huà)中剪裁尔当。如果可能莲祸,請(qǐng)?jiān)趧?dòng)畫(huà)開(kāi)始之前預(yù)先剪切圖像。

8.優(yōu)化頁(yè)面當(dāng)有大量圖片加載的時(shí)候椭迎,性能的消耗锐帜,比如降低圖片質(zhì)量來(lái)降低

參考:

  1. Flutter 應(yīng)用性能優(yōu)化最佳實(shí)踐
  2. Flutter 的性能測(cè)試和理論(剖析你的 Flutter app)
  3. Flutter 的高性能渲染原理

??推薦??:

日常學(xué)習(xí)Flutter開(kāi)發(fā)的積累

作為一個(gè)開(kāi)發(fā)者,有一個(gè)學(xué)習(xí)的氛圍跟一個(gè)交流圈子特別重要畜号,這是一個(gè)我的iOS交流群:761407670 進(jìn)群密碼000缴阎,不管你是小白還是大牛歡迎入駐 ,分享BAT,阿里面試題简软、面試經(jīng)驗(yàn)蛮拔,討論技術(shù)述暂, 大家一起交流學(xué)習(xí)成長(zhǎng)!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末建炫,一起剝皮案震驚了整個(gè)濱河市畦韭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌肛跌,老刑警劉巖艺配,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異惋砂,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)绳锅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)西饵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人鳞芙,你說(shuō)我怎么就攤上這事眷柔。” “怎么了原朝?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵驯嘱,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我喳坠,道長(zhǎng)鞠评,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任壕鹉,我火速辦了婚禮剃幌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘晾浴。我一直安慰自己负乡,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布脊凰。 她就那樣靜靜地躺著抖棘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪狸涌。 梳的紋絲不亂的頭發(fā)上切省,一...
    開(kāi)封第一講書(shū)人閱讀 49,950評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音帕胆,去河邊找鬼数尿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛惶楼,可吹牛的內(nèi)容都是我干的右蹦。 我是一名探鬼主播诊杆,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼何陆!你這毒婦竟也來(lái)了晨汹?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤贷盲,失蹤者是張志新(化名)和其女友劉穎淘这,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體巩剖,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡铝穷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了佳魔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片曙聂。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖鞠鲜,靈堂內(nèi)的尸體忽然破棺而出宁脊,到底是詐尸還是另有隱情,我是刑警寧澤贤姆,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布榆苞,位于F島的核電站,受9級(jí)特大地震影響霞捡,放射性物質(zhì)發(fā)生泄漏坐漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一碧信、第九天 我趴在偏房一處隱蔽的房頂上張望仙畦。 院中可真熱鬧,春花似錦音婶、人聲如沸慨畸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)寸士。三九已至,卻和暖如春碴卧,著一層夾襖步出監(jiān)牢的瞬間弱卡,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工住册, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留婶博,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓荧飞,卻偏偏與公主長(zhǎng)得像凡人,于是被迫代替她去往敵國(guó)和親名党。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350