检测工具 Flutter Inspector (debug模式下)
点击左上角的图标,进入select widget model 模式,此时点击相应的widget,就可在页面上显示其具体的布局区域
-
Highlight Repaints - 上图右上角操作图标的倒数第二个,若是widget发生重绘,就会改变颜色,据此发现频繁重绘的区域
-
Highlight Oversizeded Images 上图的右上角倒数第一个,该功能会检测出页面中图片实际大小大于显示大小的视图,并将图片进行倒置,便于发现,如何优化下边下边再讲
Flutter支持Release、Profile、Debug编译模式。
- Release模式,使用AOT预编译模式,预编译为机器码,通过编译生成对应架构的代码,在用户设备上直接运行对应的机器码,运行速度快,执行性能好;此模式关闭了所有调试工具,只支持真机。
- Profile模式,和Release模式类似,使用AOT预编译模式,此模式最重要的作用是可以用DevTools来检测应用的性能,做性能调试分析。
- Debug模式,使用JIT(Just in time)即时编译技术,支持常用的开发调试功能hot reload,在开发调试时使用,包括支持的调试信息、服务扩展、Observatory、DevTools等调试工具,支持模拟器和真机。
开启profile模式 VSCode launch.json中添加"flutterMode": "profile"
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: 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()},
);
如上图所示 蓝色表示 正常帧,绿色表示当前帧,红色表示出现卡顿的帧,结合当前页面和操作 定位卡顿位置
CPU Profiler
定位耗时操作
首先要运行在 profile 模式下
打开Flutter DevTools
搜索栏输入>devtools,点击 Dart: DevTools,并选择浏览器打开
点击record,就开始收集,之后点击stop
横向表示执行时间
竖向表示 调用堆栈
由此分析耗时的方法
对于低端机型的耗时操作 可开启新的线程处理
优化
布局优化
Flutter UI涉及到三棵树
- widget Tree 配置控件信息,不涉及渲染,更新代价低
- elememt Tree widget和renderObject的粘合剂
- RenderObject 真正负责渲染的树,更新代价大
1、build() 不在build中执行耗时操作,由于该方法调用的几率极大,早期开发更新 都是通过调用build进行的,可将耗时操作使用isolate实现
2、尽量将build中的widget的粒度拆小,可复用的模块抽离,拆小力度后可使用 inherteWidget、GetX等按需更新,也增加了 代码的可读性
3,尽量使用const构造器,特别是 一些通用的不更改的常量组件,比如空视图,比如加载中
4、listview构造的时候 尽量使用其 builder构造器,尽量不使用children显示视图,builder是只渲染 显示的部分
内存优化
1、const实例化,const会创建一个编译时的常量,存在一个特殊的查询列表里,仅分配一次内存
2、检测内存消耗过高的图标,上边所示的Highlight Oversizeded Images即可检测,针对大内存的图片 可自行展示大小,长列表大内存图片 可导致app崩溃,也可建立检测机制,检测列表图片的大小 过高的话 上报大数据,具体分析优化
3、listview中有大量image的情况
listview为了保证滑动的性能 会让子widget保持活动状态,这一点事通过AutomaticKeepAlive控制的,再次 向后滑动,为防止widget重新绘制,这个是由RepaintBoundaries 保证的,但是若是加载大量的图片,就会消耗大量的内存,最终可能会导致App崩溃
两个属性都设置为 false后,不可见的子widget就会被 自动处理
4、降低customScrollView listView的预渲染合理值
默认情况下 customscrollview除了渲染 屏幕显示内容外 还会渲染 上下各250区域的内容,可根据每一个item的大小和是否是低端机调整预渲染区域的大小
综合逻辑优化
1、减少自定义的 微任务内容,一般我们认为 微任务多数是系统触发的,但是我们也可以创建 比如Future.value,比如Future(() => null).then(() {})then中的任务就是微任务,以保证future执行完后立刻执行then中的处理,再比如stream任务,也可以自己创建微任务 schedmicroTask,由于微任务的执行优先级 高于UI任务,过多的微任务,会占用cpu,使UI处理滞后,造成卡顿
避免以上情况 就需要按需使用 不显示的页面相应的数据传输就停掉
2、尽可能的小粒度刷新,尽量不使用setstate刷新整个页面,将builder中的视图分成若干widget,按需刷新 可使用inheritWidget或是GetX
内存移除的检测
底层widget 一般是tabbarPage混入 WidgetsBindingObserver,
我们一般是使用这个类来检测app的生命周期 包括 后台 前台 随时可能退出,杀掉进程的状态 但是却忽略了 这里的一个检测 就是检测内存溢出的方法
/// Called when the system is running low on memory.
///
/// This method exposes the `memoryPressure` notification from
/// [SystemChannels.system].
void didHaveMemoryPressure() { }
类似于IOS中 viewController中的检测内存溢出的回调方法- (void)didReceiveMemoryWarning,
我们可以在上述方法中进行内存的手动释放
/// 释放图片组件的缓存
DefaultCacheManager().emptyCache();