檢測工具 Flutter Inspector (debug模式下)

點(diǎn)擊左上角的圖標(biāo),進(jìn)入select widget model 模式,此時(shí)點(diǎn)擊相應(yīng)的widget,就可在頁面上顯示其具體的布局區(qū)域

-
Highlight Repaints - 上圖右上角操作圖標(biāo)的倒數(shù)第二個(gè),若是widget發(fā)生重繪,就會(huì)改變顏色,據(jù)此發(fā)現(xiàn)頻繁重繪的區(qū)域
Highlight Repaints -
Highlight Oversizeded Images 上圖的右上角倒數(shù)第一個(gè),該功能會(huì)檢測出頁面中圖片實(shí)際大小大于顯示大小的視圖,并將圖片進(jìn)行倒置,便于發(fā)現(xiàn),如何優(yōu)化下邊下邊再講
Highlight Oversizeded Images
Flutter支持Release、Profile、Debug編譯模式。
- Release模式,使用AOT預(yù)編譯模式,預(yù)編譯為機(jī)器碼,通過編譯生成對應(yīng)架構(gòu)的代碼,在用戶設(shè)備上直接運(yùn)行對應(yīng)的機(jī)器碼,運(yùn)行速度快,執(zhí)行性能好;此模式關(guān)閉了所有調(diào)試工具,只支持真機(jī)。
- Profile模式,和Release模式類似,使用AOT預(yù)編譯模式,此模式最重要的作用是可以用DevTools來檢測應(yīng)用的性能,做性能調(diào)試分析。
- Debug模式,使用JIT(Just in time)即時(shí)編譯技術(shù),支持常用的開發(fā)調(diào)試功能hot reload,在開發(fā)調(diào)試時(shí)使用,包括支持的調(diào)試信息、服務(wù)擴(kuò)展、Observatory、DevTools等調(diào)試工具,支持模擬器和真機(jī)。
開啟profile模式 VSCode launch.json中添加"flutterMode": "profile"
{
// 使用 IntelliSense 了解相關(guān)屬性。
// 懸停以查看現(xiàn)有屬性的描述。
// 欲了解更多信息,請?jiān)L問: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "flutter_push",
"request": "launch",
"type": "dart",
"flutterMode": "profile"
},
]
}
Performance Overlay(性能圖層)
showPerformanceOverlay: true,
return MaterialApp(
showPerformanceOverlay: true,
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
routes: {'First': (context) => const PushFirstPage(), 'Second': (context) => const PushSecondPage(), 'Third': (context) => const PushThirdPage()},
);


如上圖所示 藍(lán)色表示 正常幀,綠色表示當(dāng)前幀,紅色表示出現(xiàn)卡頓的幀,結(jié)合當(dāng)前頁面和操作 定位卡頓位置
CPU Profiler
定位耗時(shí)操作
首先要運(yùn)行在 profile 模式下
打開Flutter DevTools
搜索欄輸入>devtools,點(diǎn)擊 Dart: DevTools,并選擇瀏覽器打開

點(diǎn)擊record,就開始收集,之后點(diǎn)擊stop

橫向表示執(zhí)行時(shí)間
豎向表示 調(diào)用堆棧
由此分析耗時(shí)的方法
對于低端機(jī)型的耗時(shí)操作 可開啟新的線程處理

優(yōu)化
布局優(yōu)化
Flutter UI涉及到三棵樹
- widget Tree 配置控件信息,不涉及渲染,更新代價(jià)低
- elememt Tree widget和renderObject的粘合劑
- RenderObject 真正負(fù)責(zé)渲染的樹,更新代價(jià)大
1、build() 不在build中執(zhí)行耗時(shí)操作,由于該方法調(diào)用的幾率極大,早期開發(fā)更新 都是通過調(diào)用build進(jìn)行的,可將耗時(shí)操作使用isolate實(shí)現(xiàn)
2、盡量將build中的widget的粒度拆小,可復(fù)用的模塊抽離,拆小力度后可使用 inherteWidget、GetX等按需更新,也增加了 代碼的可讀性
3,盡量使用const構(gòu)造器,特別是 一些通用的不更改的常量組件,比如空視圖,比如加載中
4、listview構(gòu)造的時(shí)候 盡量使用其 builder構(gòu)造器,盡量不使用children顯示視圖,builder是只渲染 顯示的部分
內(nèi)存優(yōu)化
1、const實(shí)例化,const會(huì)創(chuàng)建一個(gè)編譯時(shí)的常量,存在一個(gè)特殊的查詢列表里,僅分配一次內(nèi)存
2、檢測內(nèi)存消耗過高的圖標(biāo),上邊所示的Highlight Oversizeded Images即可檢測,針對大內(nèi)存的圖片 可自行展示大小,長列表大內(nèi)存圖片 可導(dǎo)致app崩潰,也可建立檢測機(jī)制,檢測列表圖片的大小 過高的話 上報(bào)大數(shù)據(jù),具體分析優(yōu)化

3、listview中有大量image的情況
listview為了保證滑動(dòng)的性能 會(huì)讓子widget保持活動(dòng)狀態(tài),這一點(diǎn)事通過AutomaticKeepAlive控制的,再次 向后滑動(dòng),為防止widget重新繪制,這個(gè)是由RepaintBoundaries 保證的,但是若是加載大量的圖片,就會(huì)消耗大量的內(nèi)存,最終可能會(huì)導(dǎo)致App崩潰

兩個(gè)屬性都設(shè)置為 false后,不可見的子widget就會(huì)被 自動(dòng)處理
4、降低customScrollView listView的預(yù)渲染合理值
默認(rèn)情況下 customscrollview除了渲染 屏幕顯示內(nèi)容外 還會(huì)渲染 上下各250區(qū)域的內(nèi)容,可根據(jù)每一個(gè)item的大小和是否是低端機(jī)調(diào)整預(yù)渲染區(qū)域的大小

綜合邏輯優(yōu)化
1、減少自定義的 微任務(wù)內(nèi)容,一般我們認(rèn)為 微任務(wù)多數(shù)是系統(tǒng)觸發(fā)的,但是我們也可以創(chuàng)建 比如Future.value,比如Future(() => null).then(() {})then中的任務(wù)就是微任務(wù),以保證future執(zhí)行完后立刻執(zhí)行then中的處理,再比如stream任務(wù),也可以自己創(chuàng)建微任務(wù) schedmicroTask,由于微任務(wù)的執(zhí)行優(yōu)先級(jí) 高于UI任務(wù),過多的微任務(wù),會(huì)占用cpu,使UI處理滯后,造成卡頓
避免以上情況 就需要按需使用 不顯示的頁面相應(yīng)的數(shù)據(jù)傳輸就停掉
2、盡可能的小粒度刷新,盡量不使用setstate刷新整個(gè)頁面,將builder中的視圖分成若干widget,按需刷新 可使用inheritWidget或是GetX
內(nèi)存移除的檢測
底層widget 一般是tabbarPage混入 WidgetsBindingObserver,
我們一般是使用這個(gè)類來檢測app的生命周期 包括 后臺(tái) 前臺(tái) 隨時(shí)可能退出,殺掉進(jìn)程的狀態(tài) 但是卻忽略了 這里的一個(gè)檢測 就是檢測內(nèi)存溢出的方法
/// Called when the system is running low on memory.
///
/// This method exposes the `memoryPressure` notification from
/// [SystemChannels.system].
void didHaveMemoryPressure() { }
類似于IOS中 viewController中的檢測內(nèi)存溢出的回調(diào)方法- (void)didReceiveMemoryWarning,
我們可以在上述方法中進(jìn)行內(nèi)存的手動(dòng)釋放
/// 釋放圖片組件的緩存
DefaultCacheManager().emptyCache();

