Skip to content

性能优化

写出能跑的 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_image
dart
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 方法耗时拆分组件、减少重建范围

性能优化清单

  1. ✅ 尽可能使用 const 构造函数
  2. ✅ 列表使用 ListView.builder / GridView.builder
  3. ✅ 拆分大 build 方法,减少重建范围
  4. ✅ 列表项使用唯一 Key
  5. ✅ 图片限制缓存尺寸
  6. ✅ 避免在 build 中创建对象
  7. ✅ 使用 RepaintBoundary 隔离重绘区域

下一步

基于 Flutter 官方文档整理