【Flutter】Flutter中如何避免不必要的Rebuild(面试必备)
【Flutter】Flutter中如何避免不必要的Rebuild(面试必备)
作者:ZFJ_张福杰
博客:https://zfj1128.blog.csdn.net
日期:2025-12-29
关键词:Flutter、性能、Rebuild、面试必备、性能优化
前言
在 Flutter 里,避免不必要的 rebuild 是性能优化的核心之一。
结合我平时使用 GetX / Provider / 自定义 Controller 的习惯,我这里从 原理 → 常见误区 → 实战技巧 三个层次给大家一个偏实战向的总结。
📌 我最近也在给部门招聘新的同学,这个问题我有时也会经常问到
一、核心事实
Flutter 的 rebuild ≠ 重新绘制(paint) ≠ 重新布局(layout)
我们需要知道的是:
build()频繁调用是正常的- 真正卡的是:
- build 范围过大
- build 里做了不该做的事
- 状态变化导致无关 Widget 跟着 rebuild
📌 目标不是“完全不 rebuild”,而是:让需要变的地方变,不需要变的地方不变
二、最常见的“无意义 rebuild”
1.setState 作用域过大(这个最常见)
❌ 错误示例:
setState(() {
count++;
});
在 build() 里:
Scaffold(
appBar: AppBar(),
body: Column(
children: [
Header(),
ListView(...), // 不相关
Text('$count'), // 只有它需要变
],
),
);
✅ 正确思路:状态往下沉,Widget 往下拆
class CounterText extends StatefulWidget { ... }
📌 选择合适的作用域,避免不必要的Rebuild
2. 在 build 里 new 对象 / new Controller
❌ 错误示例:
Widget build(_) {
final controller = MyController();
return ...
}
build() {
return TextStyle(fontSize: 14);
}
每次 build 都是 新引用 → diff 失败 → 子树重建
✅ 正确思路:
final TextStyle style = const TextStyle(fontSize: 14);
或放到 initState
📌 不要在build里面创建对象,避免不必要的内存开销,Widget:
const成员:final样式:static const,这是 Flutter 最“廉价”的性能优化
3. 没用 const(这是 Flutter 的“白送性能”)
❌ 错误示例:
Text('确定')
✅ 正确思路:
const Text('确定')
📌 只要参数是编译期常量,就一定要 const
4. Provider / GetX 监听范围过大
Provider 常见坑
❌ 错误示例:
final user = Provider.of<User>(context);
这会导致整个 build 都在监听。
✅ 正确思路:
context.select<User, String>((u) => u.name);
或
Consumer<User>(
builder: (_, user, __) => Text(user.name),
)
📌 只监听需要改变的控件
GetX 常见坑
❌ 错误示例:
Obx(() {
return Column(
children: [
Header(), // 不依赖 rx
ListView(), // 不依赖 rx
Text(controller.count.value.toString()),
],
);
});
✅ 正确思路:
Column(
children: [
Header(),
ListView(),
Obx(() => Text(controller.count.value.toString())),
],
);
📌 Obx 只包“最小变化单元”
5. ListView item rebuild 过度
❌ 错误示例:
ListView.builder(
itemBuilder: (_, i) => ItemWidget(item: list[i]),
)
如果 ItemWidget 是 Stateful + 依赖父级 rebuild
✅ 正确思路:
- item 尽量
const - 提供
Key
ItemWidget(
key: ValueKey(item.id),
item: item,
);
📌 Key 是 diff 的“身份证”
6. AnimatedBuilder / ValueListenable 用错
❌ 错误示例:
setState(() {
animationValue++;
});
✅ 正确思路:
AnimatedBuilder(
animation: controller,
builder: (_, child) => Transform(...),
child: const HeavyWidget(), // 不 rebuild
);
📌 child 参数 = 官方帮你做的 rebuild 隔离
7. 在 build 里做计算 / IO / map
❌ 错误示例:
build() {
final list = rawList.where(...).toList();
...
}
✅ 正确思路:
- 放到 Controller
- 放到
computed - 放到
initState - 或缓存
三、自查清单
这里我总结了一个自查清单,我们可以用这个 checklist 看自己的页面:
- setState 是否包太大?
- Obx / Consumer 是否包多余 Widget?
- build 里是否 new 对象?
- 能 const 的是否都 const?
- List item 是否有 Key?
- 是否把计算逻辑放进 build?
关于作者(ZFJ_张福杰)
- 官网:https://zfjsafe.com
- 博客:https://zfj1128.blog.csdn.net
- Github:https://github.com/zfjsyqk
- Gitee:https://gitee.com/zfj1128
- 打赏:https://zfjsafe.com/paycode
更多推荐
所有评论(0)