DevTools是什么
DevTools是Flutter开发过程中调试应用和性能调优过程中使用到的工具集合。主要作用是监察UI布局,监察CPU使用情况,监察内存使用情况,监察网络使用情况等等。帮助开发者诊断UI卡顿,分析UI各个阶段的耗时情况,量化各个阶段或者方法调用的耗时,以及内存使用情况的量化可视化,方便以及协助开发者定位解决问题。高效开发离不开高效的工具。工欲善其事,必先利其器。其实就是这个道理。
查看应用的信息
DevTools的一个标签Flutter DevTools显示配对的应用的信息,如设备CPU以及系统信息,Dart和Flutter版本信息,以及Flutter Framework以及Engine版本信息。如下图所示:
Flutter inspector
Flutter inspector是一个可视化和探索Widget树的工具,只有在debug模式下才能够显示,在Profile模式下不能显示。选中Highlight Repaints标签,此选项在所有渲染框周围绘制一个边框,该边框每次重新绘制时都会改变颜色。 例如,一个小动画可能会导致整个页面在每一帧上重新绘制。将动画包装在RepaintBoundary Widget中可将重新绘制限制为动画。此处进度指示器导致其容器重新绘制:
scala
class EverythingRepaintsPage extends StatelessWidget {
const EverythingRepaintsPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Repaint Example')),
body: const Center(
child: CircularProgressIndicator(), //此Widget可以用RepaintBoundary包裹
),
);
}
}
RepaintBoundary widget为其Widget创建一个单独的显示列表,如果子树的重新绘制时间与树的周围部分不同,这可以提高性能。如果RepaintBoundary的子树中有多个动画的组合使用,会提高性能,减少多余的刷新次数。RepaintBoundary Widget同样也有其弊端,它们可以帮助提高性能,但也需要创建新画布,这会占用额外的内存。
图片占用比较大的内存,所以图片在内存中的使用情况是一个不得不考虑的性能问题。
csharp
void showOversizedImages() {
debugInvertOversizedImages = true;
}
debugInvertOversizedImages设置为true,或者选中Flutter inspector页面的Highlight Oversized Images标签,不合理的图片使用情况会显示出来。图片宽高过大,导致图片编解码显示时间增大,同时导致内存占用过多,如果图片过多可能会导致内存溢出,导致应用稳定性减弱,引起应用崩溃。
- 最好的处理方式是缩小图片的宽高,并且把图片资源放到Asset Image资源中,图片显示最新缩小的图片。
- 稍好的处理Image Widget显示图片的时候设置cacheHeight和cacheWidth参数。
- 迫不得已可以使用ResizeImage Widget。
Memory
内存的使用情况可以通过上面的视图可以查看。内存视图可以提前发现如下几种类型的问题:
- 耗尽内存导致的崩溃。
- 超过系统存储限制导致的崩溃。
- 因为可用内存过少引起频繁的垃圾回收,导致的应用反应缓慢,甚至导致不反应的情况。
- 内存泄漏。
内存泄漏就像一个慢慢滴落的水龙头。起初它似乎并不重要,但随着时间的推移,它可能会导致大量问题,从而降低应用程序的性能。
简单介绍一下Dart和Flutter的内存。根对象:每个Dart应用程序都会创建一个根对象,该根对象直接或间接引用应用程序分配的所有其他对象。垃圾回收算法(可达性回收算法):如果在应用程序运行的某个时刻,根对象停止引用已分配的对象,则该对象将变得无法访问,这是垃圾收集器(GC)释放对象内存的信号。Java也使用根对象到对象之间的链路是否连接来确定对象能否被回收。对象与根对象之间有链接通路是对象没有被回收的根本原因,这就是内存泄漏的本质。内存泄漏是属于开发方面的编码错误,VM(虚拟机)无法避免。长生命周期的对象持有短生命周期的对象也是内存泄漏的一个类型。如何检测内存泄漏呢,如下图所示:
- Memory页面中有Diff Snapshots标签页,选中。
- 不同时刻点击两次记录内存快照按钮,生成两次内存快照。
- 选中两次内存快照,进行Diff with,分析是否有内存泄漏情况。
避免Flutter中内存泄漏的一般技巧:
- 调用相应Controller的dispose方法。例如AnimationController、TextEditingController、StreamController等。
- 取消订阅:取消对流或其他异步操作的任何有效订阅(资源的及时关闭)。
- 删除侦听器:当不再需要时,删除附加到各种组件的侦听器(例如,事件侦听器)。
- 避免保留大对象:除非绝对必要,否则请避免在小部件中保留对大对象的引用。
- 使用弱引用:在某些情况下,使用弱引用可以帮助防止内存泄漏,因为它允许在不再需要对象时对其进行垃圾回收。
Performance
查看某一帧各个阶段的耗时,在Flutter Frames选择图表中的一组,查看耗时。如下图所示,如UI阶段的耗时,以及Raster阶段的耗时。如果视图中出现红色的一组Frame,就应该关注分析这组Frame出现耗时过长的原因。 通过Android Studio的Profiler工具可以查看,绘制和渲染相关的线程包括ui线程和raster线程,执行的动图如下图所示:
总结
性能是一个调优是一个复杂而艰巨的任务,不仅需要对Dar和Flutter的知识体系有完整而深刻地认识,同时需要工具的高效配合。Flutter的DevTools就是为了解决Debug和性能调优而开发出来的工具,学好这个相关的知识之后,不仅能够开发出性能优异的应用;遇到相关的渲染的bug和性能问题,也能够游刃有余地迅速解决。知其然,知其所以然,其实就是这个道理。学习技术,我觉得应该需要"打破砂锅问到底"的劲头,同样也需要精益求精的工匠精神。应用会朝着更小,更快,更省发展。
致谢
性能调优有很多方面可以做,本文仅仅简单讲了三方面的科普,内存,性能和UI监察。希望文章对大家有所帮助,如果文章有所纰漏请不吝指教,大家共同进步。欢迎关注"技术蔡"的公众号,此公众号也是本作者的技术相关的公众号。