使用 DevTools 定位问题
优化的第一步是测量,不要靠猜。Flutter DevTools 提供了完整的性能分析工具:
flutter run --profile # 以 Profile 模式运行(接近 Release 性能)
# 然后在 VS Code / Android Studio 中打开 DevTools
重点关注 Timeline 面板中的 UI 线程和 GPU 线程。如果某一帧超过 16ms(60fps)或 8ms(120fps),就会出现丢帧卡顿。Widget Rebuild Stats 可以显示每次 setState 后哪些 Widget 发生了重建。
⚠️ 重要
永远不要在 Debug 模式下测量性能,JIT 编译和 Debug 断言会使性能大幅低于实际。始终用 Profile 或 Release 模式测试。
减少不必要的 Widget 重建
这是最高频的性能问题。setState() 会重建调用它的 Widget 及其所有子孙节点,即使大多数子 Widget 的数据并没有变化。
拆分 Widget,缩小重建范围:
// ❌ 错误:整个页面都会重建
class BadPage extends StatefulWidget {
@override
State<BadPage> createState() => _BadPageState();
}
class _BadPageState extends State<BadPage> {
int _count = 0;
@override
Widget build(BuildContext context) {
return Column(
children: [
// 这个超重的 Widget 每次都会重建!
const HeavyStaticWidget(),
Text('$_count'),
ElevatedButton(
onPressed: () => setState(() => _count++),
child: const Text('+'),
),
],
);
}
}
// ✅ 正确:只让 Counter 部分重建
class GoodPage extends StatelessWidget {
const GoodPage({super.key});
@override
Widget build(BuildContext context) {
return Column(
children: [
const HeavyStaticWidget(), // 永远不重建
const CounterWidget(), // 只有这部分重建
],
);
}
}
列表性能优化
永远使用 ListView.builder 而非 ListView,前者是懒加载的,只渲染可见区域的 item:
// ✅ 懒加载,支持百万条数据
ListView.builder(
itemCount: items.length,
// 为每个 item 提供固定高度,让 Flutter 跳过高度计算
itemExtent: 72.0,
itemBuilder: (context, index) {
return ItemWidget(item: items[index]);
},
)
// 对于不定高的复杂列表,用 cacheExtent 预加载屏幕外内容
ListView.builder(
cacheExtent: 500, // 预加载 500px 高度的内容
...
)
图片与内存优化
// 1. 指定图片尺寸,让引擎在解码时就缩放到目标尺寸,而非加载原图
Image.network(
url,
width: 200,
height: 200,
cacheWidth: 200, // 内存中缓存的宽度(像素)
cacheHeight: 200,
)
// 2. 使用 cached_network_image 插件做磁盘缓存
CachedNetworkImage(
imageUrl: url,
placeholder: (context, url) => const CircularProgressIndicator(),
errorWidget: (context, url, error) => const Icon(Icons.error),
)
Isolate 并发计算
Flutter 是单线程的(Dart 主 Isolate),CPU 密集型操作(JSON 解析、图片处理、加密)会阻塞 UI 线程导致卡顿。使用 compute() 将任务放到独立 Isolate:
// 解析大 JSON(在独立 Isolate 中执行,不阻塞 UI)
Future<List<User>> parseUsers(String jsonStr) async {
return compute(_parseUsersIsolate, jsonStr);
}
// 注意:这个函数必须是顶级函数或静态方法
List<User> _parseUsersIsolate(String jsonStr) {
final list = jsonDecode(jsonStr) as List;
return list.map((e) => User.fromJson(e)).toList();
}
const 的力量
加上 const 的 Widget 会在编译期创建,运行时直接复用相同实例,完全跳过重建过程。这是零成本优化:
// ✅ 所有固定 Widget 都加 const
const SizedBox(height: 16)
const Icon(Icons.star)
const Text('固定文字')
性能 Checklist
- ✅ 静态 Widget 加
const - ✅ 列表使用
ListView.builder - ✅ 拆分 Widget 树,缩小 setState 影响范围
- ✅ 图片指定
cacheWidth/cacheHeight - ✅ CPU 密集任务放
Isolate - ✅ 用
RepaintBoundary隔离独立绘制区域 - ✅ 避免在
build()中做计算(每帧都会执行) - ✅ Profile 模式下验证优化效果