一般情况下我们通过Flutter 技术构建的应用程序在默认情况下都是高性能的。但是呢,在编程中难免会掉入一些性能陷阱,在这一节呢我将向大家分享Flutter一些性能优化的思路并根据优化实践。
性能优化的最好时机是在编码阶段,如果你能掌握一些性能优化技巧和最佳实践,那么在编码时就可以考虑到怎么设计会性能最优,怎么实现会拖慢性能;而不是开发完成之后在去着手做性能优化,这样先污染后治理的思路。
在我们前面的Flutter开发过程中已经应用了不少Flutter性能优化的技巧以及一些最佳实践,所以说呢,在这一节主要还是对性能优化做个总结,以帮助大家更新的学习和掌握。
优化前要以 性能模式 运行 Flutter 应用
- 内存优化
- build()方法优化
- 在build()方法中执行了耗时的操作
- build()方法中堆砌了庞大的Widget
- 列表优化方法
- 案例:帧率优化
内存优化
要进行内存优化首先我们需要了解下内存的检测手段,这样我们才好进行内存优化前后的效果对比。
Flutter性能检测工具Flutter Performance
在 IDE 的 Flutter plugin 中提供了 Flutter Performance
工具,它是一个可用来检测Flutter滑动帧率和内存的工具。
我们可以从IDE的侧边栏中打开这个工具,也可以借助Dart DevTools来查看内存的使用情况:
此时可以打开一个页面或进行一些操作来观察内存的变化,如果内存突然增大很多就要特别关注是否是合理的增加,必要时要排查导致内存增加的原因和考虑对于的优化方案。
关于如何判断优化后内存有没有变化,可以通过Dart DevTools的Memory选项卡来完成,当你销毁一个FlutterEngine后可以通过GC
按钮来触发一次GC
来查看内存的变化。
build()方法优化
在我们用Flutter开发UI的时候,打交道最多的方法便是build()
了,使用build()
方法时有两个常见的陷阱,我们一起来看一下:
在build()方法中执行了耗时的操作
我们应该尽量避免在build()中执行耗时的操作,这是因为build()方法会频繁的调用,尤其是当父Widget重建的时候;所以,耗时的操作建议挪到initState()
这种不会被频繁调用的方法中;
另外,我们尽量不要在代码中进行阻塞式操作,可以将文件读取,数据库操作,网络请求这些操作通过Future来转成异步完成;另外对于CPU计算频繁的操作比如:图片压缩等可以使用Isolate来充分利用多核心CPU;
build()方法中堆砌了庞大的Wdiget
在画UI的时候有的小伙伴喜欢一把梭,其实这是一个特别不好的习惯;如果build()中返回的Widget过于庞大会导致三个问题:
- 代码可读性差:因为Flutter的布局方式的特殊性,画界面我们离不了的需要一个Wdiget嵌套一个Wdiget,但如果Wdiget嵌套太深则会导致代码的可读性变差,也不利于后期的维护和扩展;
- 复用难:由于所有的代码都在一个build()方法中,会到导致无法将公共的UI代码服用到其它的页面或模块;
- 影响性能:我们在 State 上调用 setState()时,所有build()中的 Widget 都将被重建;因此build()中返回的Widget树越大那么需要重新建的Widget越多,对性能越不利;见下图:
假如上图是我们在一个build()方法中所返回的widget树,那么当左侧红框中的widget需要更新的时候,最小的更新成本是只更新需要跟新的部分,但是由于它们都在一个State的build方法所以,调用setState()时会导致右边很多不需要更新的widget也需要重新;正确的做法是,将 setState() 的调用转移到其 UI 实际需要更改的 Widget 子树部分。
可以回想下在我们项目中有哪些地方又进行过类似的优化:
hi_flexible_header.dart
。
列表优化方法
在构建大型网格或列表时,我们要尽量避免直接使用ListView(children: [],)
或GridView(children: [],)
,因为在这种场景下会导致列表中所有的数据都会被一次性绘制出来不管列表内容是否可见,这种用法类似Android的ScrollView;所以说当你的列表中的数据量比较大时建议你用:
- ListView.builder(itemBuilder: null)
- GridView.builder(gridDelegate: null, itemBuilder: null)
这两个方法,因为这两个方法只有在屏幕的可见部分是在列表的内容才开始被创建,这种又发类似于Android的RecyclerView。
帧率优化
决定列表性能的好坏一个很关键的因素就是帧率,通常情况下手机的刷新频率为60fps,当然目前陆续出现一些高刷屏的手机能够达到90甚至120的fps。在Flutter中获取应用的帧率我们可以通过Flutter Performance选项卡来查看页面帧率:
另外可以点击上图左上角Performance overlay按钮来打开性能图层功能:
通过这个图表我们可以帮助我们分析 UI是否产生了卡顿,垂直的绿色条条代表的是当前帧,每一帧都应该在 1/60 秒(大约 16 ms)内创建并显示。如果有一帧超时而无法显示,就导致了卡顿,上述图表就会展示出来一个红色竖条。如果是在 UI 图表出现了红色竖条,则表明 Dart 代码消耗了大量资源。红色竖条表明当前帧的渲染和绘制都很耗时。
帧率优化案例
借助Flutter Performance我们对课程项目的首页进行帧率检测:
因为debug模式下Flutter的性能会受到比较大的限制,为了还原检测的真实性我们需要在分析模式运行APP。
- 在 Android Studio 和 IntelliJ 使用 Run > Flutter Run main.dart in Profile Mode 选项
- 或者通过命令行使用 --profile 参数运行
flutter run --profile
注意:模拟器不支持分析模式,可以用真机连接电脑来进行分析