性能优化
写出能跑的 Flutter 应用不难,但写出流畅的 Flutter 应用需要注意性能。本文介绍常见的性能优化方法。
Widget 重建优化
Flutter 的 UI 更新基于重建——每次 setState 或状态变化都会触发 build 方法重新执行。减少不必要的重建是性能优化的核心。
使用 const 构造函数
dart
// ✅ const 组件只创建一次,重建时直接复用
const Text('Hello')
const SizedBox(height: 16)
const EdgeInsets.all(8)
// ❌ 非必要不用 const(含运行时变量时无法用)
Text(name)
SizedBox(height: x)减少 build 方法的重建范围
dart
import 'package:flutter/material.dart';
// ❌ 整个页面重建
class MyPage extends StatefulWidget {
const MyPage({super.key});
@override
State<MyPage> createState() => _MyPageState();
}
class _MyPageState extends State<MyPage> {
int _counter = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('重建优化')),
body: Column(
children: [
// ─── ★ 不需要重建,但每次都会重建 ──────────────
const HeavyWidget(),
// ─── ☆ 不需要重建,但每次都会重建 ──────────────
Text('$_counter'), // 需要重建
ElevatedButton(
onPressed: () => setState(() => _counter++),
child: const Text('+1'),
),
],
),
);
}
}
// ✅ 拆分子组件
class OptimizedPage extends StatefulWidget {
const OptimizedPage({super.key});
@override
State<OptimizedPage> createState() => _OptimizedPageState();
}
class _OptimizedPageState extends State<OptimizedPage> {
int _counter = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('重建优化')),
body: Column(
children: [
const HeavyWidget(), // 不会重建(const)
_CounterText(count: _counter), // 只重建这个子组件
ElevatedButton(
onPressed: () => setState(() => _counter++),
child: const Text('+1'),
),
],
),
);
}
}
class _CounterText extends StatelessWidget {
final int count;
const _CounterText({required this.count});
@override
Widget build(BuildContext context) => Text('$count', style: const TextStyle(fontSize: 24));
}
class HeavyWidget extends StatelessWidget {
const HeavyWidget({super.key});
@override
Widget build(BuildContext context) {
return const Padding(
padding: EdgeInsets.all(32),
child: Text('我是一个很重的组件,不应该频繁重建'),
);
}
}
// ✅ 使用 Consumer(Provider 场景)
Consumer<CounterModel>(
builder: (context, counter, child) {
return Column(
children: [
child!, // 不重建
Text('${counter.count}'), // 只重建这部分
],
);
},
child: const HeavyWidget(), // 静态部分
)使用 Key 优化列表
dart
import 'package:flutter/material.dart';
class KeyedListPage extends StatelessWidget {
KeyedListPage({super.key});
final List<Item> items = List.generate(
20,
(i) => Item(id: 'item_$i', name: '项目 $i'),
);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Key 优化列表示例')),
body: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
key: ValueKey(items[index].id), // 唯一 Key
title: Text(items[index].name),
);
},
),
);
}
}
class Item {
final String id;
final String name;
Item({required this.id, required this.name});
}列表性能
使用 ListView.builder
dart
import 'package:flutter/material.dart';
class ListViewComparePage extends StatelessWidget {
const ListViewComparePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('ListView 对比')),
body: ListView.builder(
itemCount: 1000,
itemBuilder: (context, index) => ListTile(title: Text('Item $index')),
),
);
}
}
### 使用 itemExtent 提升滚动性能
```dart
ListView.builder(
itemExtent: 72, // 固定高度时指定,避免计算
itemCount: 1000,
itemBuilder: (context, index) => ListTile(title: Text('Item $index')),
)addAutomaticKeepAlives
dart
ListView.builder(
addAutomaticKeepAlives: false, // 不需要保持状态的列表项设为 false
itemCount: 1000,
itemBuilder: (context, index) => ListTile(title: Text('Item $index')),
)图片优化
使用 cached_network_image
bash
flutter pub add cached_network_imagedart
CachedNetworkImage(
imageUrl: 'https://example.com/photo.jpg',
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
memCacheWidth: 400, // 限制内存缓存尺寸
)图片缓存策略
- 使用
memCacheWidth/memCacheHeight限制内存中图片尺寸 - 列表中使用缩略图,详情页加载原图
- 避免在列表中加载超大图片
常见性能问题排查
使用 DevTools
bash
# 启动 DevTools
flutter pub global activate devtools
flutter pub global run devtools使用 Performance Overlay
dart
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
showPerformanceOverlay: true, // 显示性能面板
home: const Scaffold(
body: Center(child: Text('性能面板已开启')),
),
);
}
}常见问题与解决
| 问题 | 原因 | 解决 |
|---|---|---|
| 滚动卡顿 | 列表构建太慢 | 使用 ListView.builder |
| 页面切换慢 | 页面内容太重 | 延迟加载非关键内容 |
| 内存占用高 | 图片未压缩 | 限制图片缓存尺寸 |
| 动画不流畅 | build 方法耗时 | 拆分组件、减少重建范围 |
性能优化清单
- ✅ 尽可能使用
const构造函数 - ✅ 列表使用
ListView.builder/GridView.builder - ✅ 拆分大
build方法,减少重建范围 - ✅ 列表项使用唯一
Key - ✅ 图片限制缓存尺寸
- ✅ 避免在
build中创建对象 - ✅ 使用
RepaintBoundary隔离重绘区域
下一步
- 并发编程 — Isolate / compute
