基于当前的flutter项目功能基本实现,项目框架结构不清晰,代码耦合严重,重复渲染耗费资源过大等问题影响项目接下去的迭代开发,所以对当前项目先进行重构变得尤为重要。
虽然 Flutter 技术构建的应用程序在默认情况下已经非常高性能,但一开始急于完成项目,并没有就渲染上的性能问题做过多的思考。参考flutter官网,对页面的渲染性能问题需要做如下几点的考虑。
1. 减少build()的耗时
1) 避免在build()方法中执行重复且耗时的工作,因为当父widget重建时,子widget的build()方法会被重复调用
2)避免在build()方法中返回一个超大widget,将widget拆分成多个小widget,各自控制UI的渲染,避免重复渲染一个大的widget。
实践
1) 采用Provider库,分离数据及视图代码,隔绝widget。
2) 将原先在build()方法中的的一些逻辑代码提取到provider model中处理,减少build()后多次执行。
3)将大组件拆分成多个widget小组件。与业务代码耦合的组件采用provider进行数据管理,进而驱动页面UI渲染,独立小组件采用statefullwidget进行各自数据的状态管理。
4)采用Provider库中的shouldRebuild来减少不必要的渲染
Selector<QualificationModel,Tuple2<Uint8List, Uint8List>>(
shouldRebuild: (previous, next) {
if (previous.item1 != next.item1 && next.item1 != null) {
...
}
return false;
},
selector: ((_, data) => Tuple2(
data.frontIdentity,
data.backIdentity)),
builder: (context, data, _) { return ...})
2. 在必要的时候才使用一些效果
类似web开发中css3实现一些3D效果会开启GPU加速渲染,占用过多的资源,flutter中也有相同的问题。
在flutter中实现某些效果会调用性能代价很大的saveLayer()方法。因为调用 saveLayer() 会开辟一片离屏缓冲区。将内容绘制到离屏缓冲区可能会触发渲染目标切换,这些切换在较早期的 GPU 中特别慢。
避免使用一些会触发saveLayer()的widget:
- 尽量不使用
Opacity
widget - 使用Clipping时避免使用Clip.antiAliasWithSaveLayer
- ShaderMask
- ColorFilter
- 使用Chip且disabledColorAlpha != oxff 时
- 使用Text且存在overfloShader时
避免调用 saveLayer()
的方式:
- 要在图像中实现淡入淡出,请考虑使用
FadeInImage
widget,该 widget 使用 GPU 的片段着色器应用渐变不透明度。 - 要创建带圆角的矩形,而不是应用剪切矩形,考虑使用很多 widget 都提供的
borderRadius
属性。
3. 对列表或者网格列表采用懒加载
在构建大型网格或列表时,使用带有回调的惰性方法。这样,只有屏幕的可见部分是在开始时构建的。
ScrollController doneScrollController = ScrollController();
doneScrollController.addListener(() {
if (doneScrollController.position.pixels ==
doneScrollController.position.maxScrollExtent &&
!Provider.of<DoneTasksModel>(context, listen: false).isLastPage) {
Provider.of<DoneTasksModel>(context, listen: false).nextPageListData();
}
});
ListView.separated(
itemBuilder: (BuildContext context, int idx) {
return ...
},
separatorBuilder: (BuildContext context, int index) {
return ...
},
itemCount: 50,
controller: scrollController,
)