柚子快報激活碼778899分享:flutter性能優(yōu)化總結(jié)
Flutter應(yīng)用程序默認已經(jīng)具有良好的性能,因此您只需要避免常見的陷阱,就可以獲得出色的性能。
流暢度(提高渲染性能)
控制build()方法的耗時
避免在?build()?方法中進行重復且耗時的工作,因為當父 widget 重建時,子 Wdiget 的?build()?方法會被頻繁地調(diào)用。 將嵌套過多的 widget拆成不同的 widget,并進行封裝 在構(gòu)建可復用的 UI 代碼時,多使用?Widget?抽取組件,而不是函數(shù)。 請盡可能地在 widget 上使用?const?構(gòu)造函數(shù) const?在 Dart 中用于聲明常量,應(yīng)用到 widget 中就相當于告訴 Flutter,“我這個組件不會隨狀態(tài)更新而改變了?!?,因此達到了減少重建的效果。 使用 const 也需要注意如下幾點: 當const?修飾類的構(gòu)造函數(shù)時,它要求該類的所有成員都必須是final的。 const?變量只能在定義的時候初始化。
盡量減少 saveLayer 的調(diào)用(調(diào)用?saveLayer()?會開辟一片離屏緩沖區(qū))
參考:Flutter 應(yīng)用性能優(yōu)化最佳實踐 | Flutter 中文文檔 - Flutter 中文開發(fā)者網(wǎng)站 - Flutter
列表優(yōu)化
構(gòu)建大型網(wǎng)格或列表的時候,使用懶加載的方式也就是使用 ListView 和 GridView 的 builder 方法,盡量避免使用 ListView(children: [],) 或 GridView(children: [],) 對已知的所有單元格大小固定時設(shè)置屬性:itemExtent 針對于可折疊的 ListView,未展開狀態(tài)時,設(shè)置其 itemCount 為 0,這樣 item 只會在展開狀態(tài)下才進行構(gòu)建,以減少頁面第一次的打開構(gòu)建時間。
避免使用?Opacity?widget,尤其是在動畫中避免使用。可以使用?AnimatedOpacity?或?FadeInImage?代替該操作。
使用?AnimatedBuilder?時,將不需要變化的widget作為 child 傳遞給?AnimatedBuilder,從而只構(gòu)建一次。
避免在動畫中裁剪,盡可能的在動畫開始之前預(yù)先裁剪圖像。
實現(xiàn)局部刷新:
通過抽取widget為StateFulWidget包裹,使用setState刷新制定widget使用StreamBuilder實現(xiàn)局部刷Provide的解決方案設(shè)定頂級Widget,然后用consumer包裹子控件,調(diào)用更新,provider可以實現(xiàn)跨組件訪問,(跨組件訪問也可以通過context向上查詢)ValueListenableBuilder組件:可以監(jiān)聽一個值,當其變化時通過builder回調(diào)能重建界面,避免使用setState刷新GlobalKey實現(xiàn)控件的局部刷新:將需要單獨刷新的widget從復雜的布局中抽離出去,然后通過傳GlobalKey引用,這樣就可以通過GlobalKey實現(xiàn)跨組件的刷新了。StatefulBuilder組件:需要傳入builder屬性進行構(gòu)造組件,在build中可以使用StateSetter改變構(gòu)造子組件的狀態(tài),即可以不用創(chuàng)建類而實現(xiàn)一個局部刷新的組件
int a = 0;
int b = 0;
// 1、定義一個叫做“aState”的StateSetter類型方法;
StateSetter? aState;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children:
// 2、將第一個“ElevatedButton”組件嵌套在“StatefulBuilder”組件內(nèi);
StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
aState = setState;
return ElevatedButton(
onPressed: () {
a++;
// 3、調(diào)用“aState”方法對“StatefulBuilder”內(nèi)部進行刷新;
aState(() {});
},
child: Text('a : $a'),
);
},
),
ElevatedButton(
onPressed: () {
b++;
setState(() {});
},
child: Text('b : $b'),
),
],
),
),
);
}
合理使用Keys來加速Flutter性能
通過使用Keys,開發(fā)人員可以更精確地控制Flutter小部件樹的重建過程,避免不必要的重建,提高應(yīng)用程序的性能和響應(yīng)性。
保留狀態(tài):使用GlobalKey作為Key的一種常見用法是在需要保留小部件狀態(tài)的情況下。通過在重建時將相同的GlobalKey分配給相同類型的小部件,可以確保小部件在重建后保留其先前的狀態(tài),而不會丟失用戶的輸入或滾動位置。
class MyWidget extends StatefulWidget {
@override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State
final GlobalKey
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
// Widget content
);
}
}
列表中的重用:在ListView或GridView等可滾動列表中,使用Key可以幫助Flutter跟蹤列表項并在數(shù)據(jù)源更改時有效地更新列表項,而無需重新創(chuàng)建整個列表。
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
key: Key(items[index].id.toString()),
title: Text(items[index].title),
);
},
)
動態(tài)添加或移除小部件:在動態(tài)添加或移除小部件時,使用Key可以幫助Flutter正確識別要添加或移除的小部件,而不會影響其他部分的布局。
List
Container(key: Key('1'), child: Text('Widget 1')),
Container(key: Key('2'), child: Text('Widget 2')),
];
// Add a new widget
widgets.add(Container(key: Key('3'), child: Text('Widget 3')));
// Remove a widget
widgets.removeWhere((widget) => widget.key == Key('2'));
處理高消耗操作時用 isolates,但不要過度使用
釋放你不用的內(nèi)存數(shù)據(jù)
使用SKSL預(yù)熱
如果一個應(yīng)用在第一次運行時的動畫不流暢,但后來相同的動畫變得流暢,那很可能是由于著色器編譯引起的不流暢。
flutter run --profile --cache-sksl --purge-persistent-cache
flutter build apk --cache-sksl --purge-persistent-cache
使用代碼分析工具
代碼分析工具,如Flutter分析器和Lint,對于提高代碼質(zhì)量和減少錯誤和漏洞的風險非常有幫助。這些工具可以幫助識別潛在問題,防止它們成為問題,并提供改進代碼結(jié)構(gòu)和可讀性的建議。
flutter analyze lib/
使用 RepaintBoundary
RepaintBoundary是一個 Widget ,用于將其子部件的繪制內(nèi)容分離為單獨的繪制層。這樣做的主要目的是減少不必要的重繪操作,提高應(yīng)用程序的性能。當RepaintBoundary包裹一個子部件時,該子部件及其所有子部件將被視為一個整體,即使其中的其他部分發(fā)生重繪,RepaintBoundary內(nèi)的內(nèi)容也不會重繪。
RepaintBoundary的主要作用包括:
減少重繪范圍:通過將子部件包裹在RepaintBoundary中,可以將其視為一個整體,僅在該部件內(nèi)部發(fā)生重繪時才重新繪制,而不會影響到其他部分。 性能優(yōu)化:避免不必要的重繪操作,可以提高應(yīng)用程序的性能,特別是在具有復雜界面或動態(tài)內(nèi)容的情況下。 避免全局重繪:在某些情況下,只需要更新特定部分的UI,而不是整個界面。通過使用RepaintBoundary,可以限制重繪的范圍,避免全局重繪。 邊界控制:可以通過RepaintBoundary來控制重繪的邊界,確保只在需要時才進行重繪操作,而不會影響到其他部分。
RepaintBoundary是一個有用的工具,可以幫助優(yōu)化Flutter應(yīng)用程序的性能,特別是在需要控制重繪范圍和避免不必要重繪操作的情況下。在開發(fā)復雜界面或需要動態(tài)更新的應(yīng)用程序時,合理使用RepaintBoundary可以提高應(yīng)用程序的性能和用戶體驗。
原生與flutter混合開發(fā)時flutter頁面啟動速度優(yōu)化
啟動速度優(yōu)化最常用的方法是空間換時間法
方式一、通過flutter引擎預(yù)加載來達到頁面秒開的效果:
/**
* 預(yù)加載flutter
*/
fun preLoad(context: Context) {
//在線程空閑時執(zhí)行預(yù)加載任務(wù)
Looper.myQueue().addIdleHandler {
initFlutterEngine(context, MODULE_NAME_FAVORITE)
initFlutterEngine(context, MODULE_NAME_RECOMMEND)
false
}
}
/**
* 獲取預(yù)加載的flutter
*/
fun getCachedFlutterEngine(moduleName: String, context: Context?): FlutterEngine {
var engine = FlutterEngineCache.getInstance()[moduleName]
if (engine == null && context != null) {
engine = initFlutterEngine(context, moduleName)
}
return engine!!
}
/**
* 銷毀flutterengine
*/
fun destroyCached(moduleName: String) {
FlutterEngineCache.getInstance()[moduleName]?.apply {
destroy()
}
FlutterEngineCache.getInstance().remove(moduleName)
}
fun hastCached(moduleName: String): Boolean {
return FlutterEngineCache.getInstance().contains(moduleName)
}
/**
* 初始化flutter
*/
private fun initFlutterEngine(context: Context, moduleName: String): FlutterEngine {
val flutterEngine = FlutterEngine(context)
flutterEngine.dartExecutor.executeDartEntrypoint(
DartExecutor.DartEntrypoint(
FlutterMain.findAppBundlePath(),
moduleName
)
)
FlutterEngineCache.getInstance().put(moduleName, flutterEngine)
return flutterEngine
}
方式二、預(yù)加載dartVM
/**
* 預(yù)加載DartVM
*/
fun preLoadDartVM(context: Context) {
val flutterLoader = FlutterLoader()
val settings = FlutterLoader.Settings()
flutterLoader.startInitialization(context, settings)
val mainHandler = Handler(Looper.getMainLooper())
flutterLoader.ensureInitializationCompleteAsync(
context, arrayOf(), mainHandler
) {
HiLog.i("flutter preLoadDartVM done")
}
}
兩種方式都是有一定的內(nèi)存成本的,對內(nèi)存的消耗上:引擎預(yù)加載>DartVM預(yù)加載;對啟動性能的提升上:引擎預(yù)加載>DartVM預(yù)加載,所以要不要空間換時間,還要看app具體情況。如果app內(nèi)存壓力不大,并且預(yù)判用戶接下來會訪問flutter業(yè)務(wù),那使用這個優(yōu)化就能帶來很好的價值;反之,則可能造成資源浪費,意義不大。
應(yīng)用程序的大小
執(zhí)行如下命令,可以查看詳細信息:
flutter build apk --analyze-size --target-platform android-arm64
代碼混淆
flutter build apk --obfuscate --split-debug-info=./out/android/app.android-arm64.symbols
資源文件優(yōu)化 避免使用過多的第三方庫 圖片優(yōu)化:1.壓縮 PNG 和 JPEG 文件2.使用WebP格式替換PNG圖片3.使用三方庫壓縮flutter_image_compress
//https://pub.dev/packages/flutter_image_compress
Future
var result = await FlutterImageCompress.compressWithFile(
file.absolute.path,
minWidth: 2300,
minHeight: 1500,
quality: 94,
rotate: 90,
);
print(file.lengthSync());
print(result.length);
return result;
}
移除未使用的依賴庫和資源。其中Android端 buildTypes {
release {
// 移除無用的資源文件
shrinkResources true
// ZipAlign 優(yōu)化
zipAlignEnabled true
// 設(shè)置混淆
minifyEnabled true
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.release
}
} minifyEnabled:是否啟用代碼縮減 如果將 minifyEnabled 屬性設(shè)為 true,系統(tǒng)會默認啟用 R8 代碼縮減功能。代碼縮減(也稱為“搖樹優(yōu)化”)是指移除 R8 確定在運行時不需要的代碼的過程。此過程可以大大減小應(yīng)用的大小,例如,當您的應(yīng)用包含許多庫依賴項,但只使用它們的一小部分功能時。 shrinkResources:是否啟用縮減資源 資源縮減只有在與代碼縮減配合使用時才能發(fā)揮作用。在代碼縮減器移除所有不使用的代碼后,資源縮減器便可確定應(yīng)用仍要使用的資源。 ? android端可以設(shè)置cpu架構(gòu)
ndk {
// armeabi:已經(jīng)淘汰(0%)
// armeabi-v7a:曾經(jīng)主流的架構(gòu)平臺(20%)
// arm64-v8a:目前主流架構(gòu)平臺(80%)
abiFilters "armeabi-v7a", "arm64-v8a"
// abiFilters "arm64-v8a"
}
? ? ? ?
柚子快報激活碼778899分享:flutter性能優(yōu)化總結(jié)
文章來源
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。