一、构建优化(Build Optimization)
1.1 使用 const 构造函数
原理:const Widget 在编译时创建,不会在每次 build 时重建。
scss
// ❌ 错误:每次都创建新对象
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(16),
child: Text('标题'),
);
}
// ✅ 正确:使用 const
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(16),
child: const Text('标题'),
);
}
优化建议:
- 静态文本、图标、样式等都用 const
- 善用 IDE 提示,它会提示哪里可以加 const
- 对于不变的 Widget 树,整个都标记为 const
1.2 避免在 build 方法中创建对象
php
// ❌ 错误:每次 build 都创建新样式
Widget build(BuildContext context) {
return Text(
'内容',
style: TextStyle(fontSize: 16, color: Colors.blue), // 每次重建
);
}
// ✅ 正确:提取为常量
static const _textStyle = TextStyle(fontSize: 16, color: Colors.blue);
Widget build(BuildContext context) {
return Text('内容', style: _textStyle);
}
1.3 拆分 Widget,缩小重建范围
scala
// ❌ 错误:整个页面重建
class MyPage extends StatefulWidget {
@override
State<MyPage> createState() => _MyPageState();
}
class _MyPageState extends State<MyPage> {
int _counter = 0;
@override
Widget build(BuildContext context) {
return Column(
children: [
Header(), // 不需要重建,但会重建
Text('计数: $_counter'), // 需要重建
Footer(), // 不需要重建,但会重建
],
);
}
}
// ✅ 正确:拆分可变部分
class MyPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
const Header(), // const,不会重建
CounterWidget(), // 只有这部分重建
const Footer(), // const,不会重建
],
);
}
}
class CounterWidget extends StatefulWidget {
@override
State<CounterWidget> createState() => _CounterWidgetState();
}
1.4 使用 Builder 延迟构建
less
// ❌ 错误:一次性构建大量 Widget
Column(
children: List.generate(1000, (index) => ListTile(title: Text('$index'))),
)
// ✅ 正确:按需构建
ListView.builder(
itemCount: 1000,
itemBuilder: (context, index) => ListTile(title: Text('$index')),
)
二、渲染优化(Rendering Optimization)
2.1 使用 RepaintBoundary 隔离重绘
原理:创建独立的绘制层,避免不必要的重绘传播。
less
// ✅ 隔离频繁变化的动画区域
Column(
children: [
const Text('静态标题'),
RepaintBoundary(
child: AnimatedWidget(), // 动画只重绘这部分
),
const Text('静态底部'),
],
)
适用场景:
- 复杂动画
- 频繁更新的区域(如时钟、进度条)
- 列表项中的复杂 Widget
2.2 避免使用 Opacity 做淡入淡出
less
// ❌ 错误:Opacity 会导致昂贵的离屏渲染
Opacity(
opacity: 0.5,
child: ComplexWidget(),
)
// ✅ 正确:使用 AnimatedOpacity
AnimatedOpacity(
opacity: 0.5,
duration: Duration(milliseconds: 300),
child: ComplexWidget(),
)
// ✅ 或者直接用颜色透明度
Container(
color: Colors.blue.withOpacity(0.5),
child: ComplexWidget(),
)
2.3 避免使用 ClipPath/ClipRRect 的昂贵裁剪
less
// ❌ 较慢:复杂路径裁剪
ClipPath(
clipper: CustomClipper(),
child: ComplexWidget(),
)
// ✅ 较快:使用 DecoratedBox + borderRadius
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
),
child: ComplexWidget(),
)
2.4 减少 saveLayer 调用
会触发 saveLayer 的操作(都很昂贵):
- Opacity(部分情况)
- ColorFilter
- ShaderMask
- BackdropFilter
- 带透明度的 ClipRRect
less
// ❌ 避免这种写法
Opacity(
opacity: 0.5,
child: Container(
decoration: BoxDecoration(
color: Colors.blue,
boxShadow: [BoxShadow(...)],
),
),
)
// ✅ 改为直接设置颜色透明度
Container(
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.5),
boxShadow: [BoxShadow(...)],
),
)
三、列表优化(List Optimization)
3.1 使用 ListView.builder 而非 ListView
less
// ❌ 错误:一次性创建所有 Widget
ListView(
children: List.generate(10000, (i) => ListTile(title: Text('$i'))),
)
// ✅ 正确:按需加载
ListView.builder(
itemCount: 10000,
itemBuilder: (context, index) => ListTile(title: Text('$index')),
)
3.2 添加 itemExtent 或 prototypeItem
less
// ✅ 指定固定高度,提升滚动性能
ListView.builder(
itemCount: 1000,
itemExtent: 56.0, // 每项固定高度
itemBuilder: (context, index) => ListTile(title: Text('$index')),
)
// ✅ 或使用 prototypeItem
ListView.builder(
itemCount: 1000,
prototypeItem: const ListTile(title: Text('原型')),
itemBuilder: (context, index) => ListTile(title: Text('$index')),
)
3.3 使用 AutomaticKeepAlive 保持状态
scala
class MyListItem extends StatefulWidget {
@override
State<MyListItem> createState() => _MyListItemState();
}
class _MyListItemState extends State<MyListItem>
with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true; // 保持状态不被销毁
@override
Widget build(BuildContext context) {
super.build(context); // 必须调用
return ExpansiveWidget(); // 展开收起的复杂组件
}
}
3.4 缓存复杂计算结果
scala
class MyListItem extends StatelessWidget {
final String data;
const MyListItem(this.data);
// ❌ 错误:每次 build 都计算
@override
Widget build(BuildContext context) {
final processed = expensiveProcessing(data);
return Text(processed);
}
}
// ✅ 正确:使用 Memo 或在外部处理
class MyListItem extends StatelessWidget {
final String data;
final String processed; // 预处理好的数据
const MyListItem(this.data, this.processed);
@override
Widget build(BuildContext context) {
return Text(processed);
}
}
四、图片优化(Image Optimization)
4.1 使用合适的图片格式和尺寸
less
// ❌ 错误:加载原图(10MB,4000x3000)
Image.network('https://example.com/huge-image.jpg')
// ✅ 正确:使用缩略图或指定尺寸
Image.network(
'https://example.com/thumbnail.jpg',
width: 100,
height: 100,
cacheWidth: 100, // 解码时缩放,节省内存
cacheHeight: 100,
)
4.2 使用 cached_network_image 缓存网络图片
less
import 'package:cached_network_image/cached_network_image.dart';
// ✅ 自动缓存,避免重复下载
CachedNetworkImage(
imageUrl: 'https://example.com/image.jpg',
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
memCacheWidth: 200, // 内存缓存优化
maxWidthDiskCache: 400, // 磁盘缓存优化
)
4.3 预加载图片
scss
@override
void didChangeDependencies() {
super.didChangeDependencies();
// 预加载下一页可能用到的图片
precacheImage(AssetImage('assets/next_page.png'), context);
precacheImage(NetworkImage('https://example.com/image.jpg'), context);
}
4.4 使用 ResizeImage 缩小图片
less
// ✅ 解码时就缩放,节省内存
Image(
image: ResizeImage(
NetworkImage('https://example.com/image.jpg'),
width: 300,
height: 300,
),
)
五、状态管理优化
5.1 选择合适的状态管理方案
scala
// ❌ 简单应用过度设计
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Provider<ComplexStore>(
create: (_) => ComplexStore(),
child: MaterialApp(...),
);
}
}
// ✅ 简单情况用 StatefulWidget 或 ValueNotifier
class CounterWidget extends StatefulWidget {
@override
State<CounterWidget> createState() => _CounterWidgetState();
}
// ✅ 复杂情况用 Provider/Riverpod/Bloc
5.2 使用 ValueListenableBuilder 局部刷新
scala
class MyWidget extends StatefulWidget {
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
final _counter = ValueNotifier<int>(0);
@override
Widget build(BuildContext context) {
return Column(
children: [
const Text('静态标题'), // 不会重建
ValueListenableBuilder<int>(
valueListenable: _counter,
builder: (context, value, child) {
return Text('计数: $value'); // 只有这里重建
},
),
ElevatedButton(
onPressed: () => _counter.value++,
child: const Text('增加'),
),
],
);
}
@override
void dispose() {
_counter.dispose();
super.dispose();
}
}
5.3 使用 Selector 精确监听
dart
// 使用 Provider + Selector
Consumer<MyModel>(
builder: (context, model, child) {
return Text('${model.counter}'); // model 任何变化都会重建
},
)
// ✅ 改为 Selector,只监听特定字段
Selector<MyModel, int>(
selector: (context, model) => model.counter, // 只监听 counter
builder: (context, counter, child) {
return Text('$counter'); // 只有 counter 变化才重建
},
)
六、异步与网络优化
6.1 使用 FutureBuilder/StreamBuilder 避免手动管理状态
scss
// ✅ 自动处理加载、成功、失败状态
FutureBuilder<List<Item>>(
future: fetchItems(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView(children: snapshot.data!.map(...).toList());
} else if (snapshot.hasError) {
return Text('错误: ${snapshot.error}');
}
return CircularProgressIndicator();
},
)
6.2 使用 compute 执行耗时计算
scss
// ❌ 错误:在主线程执行耗时操作
List<Item> parseData(String json) {
return expensiveParsing(json); // 阻塞 UI
}
// ✅ 正确:在后台线程执行
Future<List<Item>> parseData(String json) async {
return compute(_parseInBackground, json);
}
List<Item> _parseInBackground(String json) {
return expensiveParsing(json);
}
6.3 防抖和节流
scss
// 搜索框防抖
Timer? _debounce;
void onSearchChanged(String query) {
_debounce?.cancel();
_debounce = Timer(const Duration(milliseconds: 500), () {
performSearch(query); // 500ms 后才执行
});
}
@override
void dispose() {
_debounce?.cancel();
super.dispose();
}
七、内存优化
7.1 及时释放资源
scala
class MyWidget extends StatefulWidget {
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
late AnimationController _controller;
late StreamSubscription _subscription;
@override
void initState() {
super.initState();
_controller = AnimationController(vsync: this, ...);
_subscription = stream.listen(...);
}
@override
void dispose() {
_controller.dispose(); // ✅ 释放动画控制器
_subscription.cancel(); // ✅ 取消订阅
super.dispose();
}
@override
Widget build(BuildContext context) => Container();
}
7.2 避免内存泄漏
scala
// ❌ 错误:闭包持有 State 引用
class _MyWidgetState extends State<MyWidget> {
void startTimer() {
Timer.periodic(Duration(seconds: 1), (timer) {
setState(() {}); // 即使 Widget 销毁,timer 仍在运行
});
}
}
// ✅ 正确:保存引用并取消
class _MyWidgetState extends State<MyWidget> {
Timer? _timer;
void startTimer() {
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
if (mounted) { // 检查是否仍然挂载
setState(() {});
}
});
}
@override
void dispose() {
_timer?.cancel();
super.dispose();
}
}
7.3 使用弱引用或事件总线
scss
// 使用 event_bus 避免直接持有引用
final EventBus eventBus = EventBus();
// 订阅
StreamSubscription subscription = eventBus.on<UserEvent>().listen((event) {
// 处理事件
});
// 取消订阅
subscription.cancel();
八、启动优化
8.1 延迟初始化
scss
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// ✅ 只初始化必要的服务
await initCriticalServices();
runApp(MyApp());
// ✅ 应用启动后再初始化非关键服务
initNonCriticalServices();
}
8.2 使用占位符快速渲染首屏
scala
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: FutureBuilder(
future: loadInitialData(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return HomePage();
}
return SplashScreen(); // ✅ 轻量级占位屏幕
},
),
);
}
}
九、性能监控与分析
9.1 使用 Flutter DevTools
bash
# 运行应用后打开 DevTools
flutter run
# 然后在浏览器打开 DevTools 链接
重点关注:
- Performance 页面:查看帧率、重建次数
- Memory 页面:监控内存使用
- Network 页面:分析网络请求
9.2 使用 Timeline
javascript
import 'dart:developer';
void expensiveOperation() {
Timeline.startSync('expensiveOperation');
// 执行操作
Timeline.finishSync();
}
9.3 检查过度重建
scala
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('MyWidget build'); // 监控重建次数
return Container();
}
}
十、编译优化
10.1 使用 Profile/Release 模式测试性能
arduino
# ❌ Debug 模式性能差,不能作为参考
flutter run
# ✅ Profile 模式:保留调试信息 + 优化性能
flutter run --profile
# ✅ Release 模式:最佳性能
flutter run --release
flutter build apk --release
flutter build ios --release
10.2 启用代码混淆
ini
# Android
flutter build apk --obfuscate --split-debug-info=/<project-name>/<directory>
# iOS
flutter build ios --obfuscate --split-debug-info=/<project-name>/<directory>
10.3 分析包体积
css
# 分析包大小
flutter build apk --analyze-size
flutter build appbundle --analyze-size
# 查看详细信息
flutter build apk --target-platform android-arm64 --analyze-size
性能优化检查清单
每个页面发布前检查:
- 使用了 const 构造函数
- 避免在 build 中创建对象
- 大列表使用了 .builder
- 图片指定了合适的尺寸
- 没有不必要的重建
- 动画使用了 RepaintBoundary
- 资源在 dispose 中释放
- 在 Profile 模式下测试过性能
性能指标参考:
- 帧率:保持 60fps(或 120fps for 高刷屏)
- 卡顿:UI 线程不超过 16ms,Raster 线程不超过 16ms
- 内存:不出现明显泄漏,增长趋势平稳
- 启动时间:冷启动 < 3秒,热启动 < 1秒