7.3 优化实践

性能优化要以数据为导向,先测量再优化。本节介绍渲染、布局、内存、图片和异步五大优化方向的具体实践。


一、渲染性能优化

1.1 const 构造函数(最高效优化手段)

dart 复制代码
// ❌ 每次 build() 都创建新实例
Widget build(BuildContext context) {
  return Padding(
    padding: EdgeInsets.all(16), // 没有 const
    child: Text('Static Text'),  // 没有 const
  );
}

// ✅ const → Flutter 复用同一实例,跳过重建
Widget build(BuildContext context) {
  return const Padding(
    padding: EdgeInsets.all(16),
    child: Text('Static Text'),
  );
}

规则: 只要子 Widget 的属性在编译期可知且不变,都应加 const

1.2 RepaintBoundary(隔离重绘范围)

dart 复制代码
// ❌ 动画更新时,整个页面的 RenderObject 都被标记为 dirty
class ChatPage extends StatelessWidget {
  Widget build(BuildContext context) {
    return Column(children: [
      TypingIndicator(), // 每秒闪烁动画
      MessageList(),     // 大量静态消息列表
    ]);
  }
}

// ✅ 用 RepaintBoundary 隔离,动画更新不影响 MessageList
class ChatPage extends StatelessWidget {
  Widget build(BuildContext context) {
    return Column(children: [
      RepaintBoundary(child: TypingIndicator()), // 动画在独立层
      RepaintBoundary(child: MessageList()),     // 静态内容不会因动画重绘
    ]);
  }
}

1.3 精细化 setState

dart 复制代码
// ❌ 整个 StatefulWidget 都重建
class ProductPage extends StatefulWidget { ... }
class _ProductPageState extends State<ProductPage> {
  bool isFavorited = false;

  Widget build(BuildContext context) {
    return Column(children: [
      ProductHeader(),           // 随 isFavorited 无谓重建
      ProductDescription(),      // 随 isFavorited 无谓重建
      FavoriteButton(            // 只有这里需要更新
        isFavorited: isFavorited,
        onTap: () => setState(() => isFavorited = !isFavorited),
      ),
    ]);
  }
}

// ✅ 方案一:提取 FavoriteButton 为独立 StatefulWidget
// ✅ 方案二:使用 ValueNotifier + ValueListenableBuilder
class _ProductPageState extends State<ProductPage> {
  final _isFavorited = ValueNotifier<bool>(false);

  Widget build(BuildContext context) {
    return Column(children: [
      const ProductHeader(),       // const,永不重建
      const ProductDescription(),  // const,永不重建
      ValueListenableBuilder<bool>(
        valueListenable: _isFavorited,
        builder: (_, value, __) => FavoriteButton(
          isFavorited: value,
          onTap: () => _isFavorited.value = !_isFavorited.value,
        ),
      ),
    ]);
  }
}

二、布局性能优化

2.1 避免频繁重建深层树

dart 复制代码
// ❌ 将回调定义在 build() 中,每次重建都创建新函数对象
Widget build(BuildContext context) {
  return ListView.builder(
    itemBuilder: (context, index) {
      return ListTile(
        onTap: () => _handleTap(index), // 每次创建新闭包
      );
    },
  );
}

// ✅ 将静态子树提取为 const 或字段
class _MyState extends State<MyWidget> {
  late final Widget _staticHeader;

  @override
  void initState() {
    super.initState();
    _staticHeader = const ExpensiveHeaderWidget(); // 只创建一次
  }

  @override
  Widget build(BuildContext context) {
    return Column(children: [
      _staticHeader,   // 不会重建
      _buildBody(),
    ]);
  }
}

2.2 Sliver 优化长列表

dart 复制代码
// ❌ Column + SingleChildScrollView:所有 Widget 一次性构建
SingleChildScrollView(
  child: Column(children: manyWidgets),
)

// ✅ CustomScrollView + Sliver:按需懒加载
CustomScrollView(
  slivers: [
    // 折叠头部
    const SliverAppBar(
      expandedHeight: 200,
      pinned: true,
      flexibleSpace: FlexibleSpaceBar(title: Text('标题')),
    ),
    // 分组标题(固定)
    const SliverToBoxAdapter(child: CategoryHeader()),
    // 网格懒加载
    SliverGrid(
      delegate: SliverChildBuilderDelegate(
        (context, index) => ProductCard(product: products[index]),
        childCount: products.length,
      ),
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
      ),
    ),
    // 列表懒加载
    SliverList(
      delegate: SliverChildBuilderDelegate(
        (context, index) => RecommendItem(item: recommendations[index]),
        childCount: recommendations.length,
      ),
    ),
  ],
)

三、内存管理

3.1 正确 dispose 资源

dart 复制代码
class _VideoPlayerState extends State<VideoPlayer> {
  late VideoPlayerController _controller;
  StreamSubscription? _subscription;
  AnimationController? _animController;

  @override
  void initState() {
    super.initState();
    _controller = VideoPlayerController.networkUrl(Uri.parse(widget.url));
    _animController = AnimationController(vsync: this, duration: ...);
    _subscription = eventStream.listen(_handleEvent);
  }

  @override
  void dispose() {
    _controller.dispose();       // ✅ 释放视频播放器
    _animController?.dispose();  // ✅ 释放动画控制器
    _subscription?.cancel();     // ✅ 取消流订阅
    super.dispose();
  }
}

3.2 图片内存优化

dart 复制代码
// ✅ 限制图片缓存尺寸(避免加载超大原图)
Image.network(
  imageUrl,
  cacheWidth: 300,    // 解码为 300 像素宽(DPR 已考虑)
  cacheHeight: 300,   // 避免解码 4000x4000 的原图
  fit: BoxFit.cover,
)

// ✅ 控制全局图片缓存大小
void main() {
  PaintingBinding.instance.imageCache.maximumSize = 200;       // 最多 200 张
  PaintingBinding.instance.imageCache.maximumSizeBytes = 50 << 20; // 50MB
  runApp(const MyApp());
}

// ✅ 不需要时手动清理图片缓存
imageCache.clear();
imageCache.clearLiveImages();

四、图片与缓存优化

yaml 复制代码
dependencies:
  cached_network_image: ^3.3.1
dart 复制代码
// 带缓存、占位符和错误处理的图片加载
CachedNetworkImage(
  imageUrl: product.imageUrl,
  width: 200,
  height: 200,
  fit: BoxFit.cover,
  placeholder: (context, url) => const ShimmerWidget(), // 骨架屏
  errorWidget: (context, url, error) => const Icon(Icons.broken_image),
  memCacheWidth: 400,  // 内存缓存尺寸(节省内存)
  maxWidthDiskCache: 800, // 磁盘缓存最大宽度
)

五、异步与后台计算

5.1 compute(简单后台任务)

dart 复制代码
// 在主线程:
final result = await compute(parseProductsJson, jsonString);

// 在 Isolate 中执行(独立线程):
List<Product> parseProductsJson(String jsonString) {
  final list = jsonDecode(jsonString) as List;
  return list.map((e) => Product.fromJson(e)).toList();
}

// 注意:compute 的函数必须是顶层函数或 static 方法

5.2 Isolate.spawn(复杂后台任务)

dart 复制代码
Future<void> runHeavyTask() async {
  final receivePort = ReceivePort();

  await Isolate.spawn(
    _heavyTaskEntry,
    receivePort.sendPort,
  );

  final result = await receivePort.first;
  print('Result: $result');
}

// 必须是顶层函数
void _heavyTaskEntry(SendPort sendPort) {
  // 执行耗时计算
  final result = _complexCalculation();
  sendPort.send(result);
}

小结

优化方向 关键手段 效果
渲染 constRepaintBoundary 减少不必要重建和重绘
布局 Sliver 懒加载、提取静态树 降低初始化和重建开销
内存 dispose 资源、控制图片缓存尺寸 防止内存泄漏
图片 CachedNetworkImagecacheWidth 减少内存和解码开销
异步 computeIsolate.spawn 耗时操作移离主线程

👉 下一章:八、工程化与模块化

相关推荐
Lsk_Smion2 小时前
Sability安卓(三)_基础开发知识扫盲,开学XML......
android·java·android studio·安卓
三少爷的鞋3 小时前
Android 慢性病之拒绝"带病"上线:为什么 ANR 是必须根除的代码 HP?
android
草莓熊Lotso3 小时前
Linux 线程深度剖析:线程 ID 本质、地址空间布局与 pthread 源码全解
android·linux·运维·服务器·数据库·c++
私人珍藏库3 小时前
【Android】Shizuku升级版-Stellar-提高软件权限
android·app·工具·软件·多功能
白毛大侠3 小时前
# MySQL InnoDB 隔离级别与 MVCC 完全解析
android·数据库·mysql
见山是山-见水是水10 小时前
鸿蒙flutter第三方库适配 - 读书笔记
flutter·华为·harmonyos
Utopia^11 小时前
鸿蒙flutter第三方库适配 - 图片压缩工具
flutter·华为·harmonyos
冬奇Lab13 小时前
MediaPlayer 播放器架构:NuPlayer 的 Source/Decoder/Renderer 三驾马车
android·音视频开发·源码阅读
见山是山-见水是水14 小时前
鸿蒙flutter第三方库适配 - 车辆管理
flutter·华为·harmonyos