检查了下项目中存在的性能优化,故做了如下调整。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

性能优化:内存与生命周期优化

这里记录下 「内存与生命周期」 三项优化的实现方式与涉及代码。


一、要达到的目标

  • 1.1 网络图片组件未做取消与复用:请求发出后若组件被 dispose(如列表快速滑动),请求不会取消;需在 dispose 时放弃当前等待(通过 Completer),并与现有单例 Dio + 内存缓存配合,同一 URL 只发起一次请求。
  • 1.2 列表项未使用 RepaintBoundary:复杂 item(图片 + 渐变 + 文字)重绘时可能影响整列表的 repaint 区域;对每个 item 根 Widget 包一层 RepaintBoundary,将重绘隔离在单格内。
  • 1.3 ListView/GridView 的 cacheExtent:未设置时使用默认值;适当增大 cacheExtent(如 400)让即将进入视口的 item 提前构建/加载,减少滚动时的等待感。

对应文档.doc/性能优化建议.md 第四部分「内存与生命周期」。


首页

二、思路

  1. 2.1:在 ImageCacheService.getImage 中增加可选参数 abandonFutureFuture<void>);组件在请求时传入一个 Completer<void>.future,在 dispose 或 URL 变更时 completer.complete(),使该次等待立即结束并返回 null,不阻塞已 dispose 的组件;不取消底层 Dio 请求,其他等待同一 URL 的调用仍可拿到结果。
  2. 2.2:在首页(PageView 单页、GridView 格子)、发现页(卡片)、收藏页(ListTile)的每个 item 根节点外包一层 RepaintBoundary
  3. 2.3:为首页 GridView.builder、发现页 GridView.builder、收藏页 ListView.builder 设置 cacheExtent: 400(单位逻辑像素)。

三、涉及文件

文件 说明
lib/services/image_cache_service.dart getImage 增加可选 abandonFuture;新增 _raceWithAbandon,与 abandonFuture 竞态,先完成时立即返回 null。
lib/widgets/network_image_widget.dart 状态中持有 Completer<void>? _abandonCompleter_loadImage 前 complete 旧 completer 并创建新 completer,调用 getImage(url, abandonFuture: completer.future)dispose_abandonCompleter?.complete();请求返回后若 _abandonCompleter!.isCompleted 则不 setState。
lib/pages/home_page.dart _buildGridImageItem_buildImagePage 根节点包 RepaintBoundaryGridView.builder 设置 cacheExtent: 400
lib/pages/search_page.dart itemBuilder 中每个 _WorkCard 外包 RepaintBoundaryGridView.builder 设置 cacheExtent: 400
lib/pages/favorites_page.dart itemBuilder 中每个 ListTile 外包 RepaintBoundaryListView.builder 设置 cacheExtent: 400

无新增 pub 依赖;使用 Dart 标准库 dart:asyncCompleter


四、实现要点

4.1 请求取消与竞态

  • 为何不直接取消 Dio 请求?
    同一 URL 可能被多个组件同时请求,ImageCacheService_inFlight 做去重,只发一次 Dio 请求。若因某一个组件 dispose 就取消该请求,会连累其他等待同一 URL 的组件。因此采用「仅取消该组件的等待」:用 Future.any([actual, abandonFuture.then((_) => null)]),abandon 时该调用立即得到 null,底层请求继续,结果仍写入缓存供他人使用。

  • 组件侧:每次 _loadImage_abandonCompleter?.complete() 并新建 Completer<void>()dispose_abandonCompleter?.complete();请求返回后除 _disposedmounted 外再判断 _abandonCompleter!.isCompleted,避免 URL 切换或 dispose 后误触发 setState。

4.2 RepaintBoundary

  • 位置:每个列表 item 的 Widget 外包一层,保证该 item 重绘时不影响列表其他格子。
  • 首页:单列滑动每页 _buildImagePage 整页、网格每格 _buildGridImageItem 整格包一层。
  • 发现页_WorkCard 整卡包一层。
  • 收藏页:每个 ListTile 包一层。

4.3 cacheExtent

  • 取值:文档建议 200–500,本次统一取 400(逻辑像素),便于真机根据内存与流畅度再微调。
  • PageView:Flutter 的 PageView 基于 Viewport,未在本次对 PageView 设置 cacheExtent(其预加载机制与 ListView/GridView 不同,且首页已主要用 GridView/PageView 的 item 数量控制)。

五、关键代码位置

5.1 ImageCacheService(image_cache_service.dart)

  • getImage 签名与竞态
Future<Uint8List?> getImage(String url, {Future<void>? abandonFuture}) async {
  // ... 缓存与 _inFlight 逻辑 ...
  return _raceWithAbandon(future, abandonFuture);
}

Future<Uint8List?> _raceWithAbandon(Future<Uint8List?> actual, Future<void>? abandonFuture) async {
  if (abandonFuture == null) return actual;
  return Future.any<Uint8List?>([
    actual,
    abandonFuture.then((_) => Future<Uint8List?>.value(null)),
  ]);
}

5.2 NetworkImageWidget(network_image_widget.dart)

  • 状态与 disposeCompleter<void>? _abandonCompleter_loadImage() 内新建 Completer 并传入 getImage(..., abandonFuture: _abandonCompleter!.future);返回后 if (_disposed || !mounted || _abandonCompleter!.isCompleted) returndispose()_abandonCompleter?.complete()

5.3 列表 RepaintBoundary 与 cacheExtent

  • 首页_buildGridImageItem 根为 RepaintBoundary(child: GestureDetector(...))_buildImagePage 根为 RepaintBoundary(child: GestureDetector(...))GridView.builder(..., cacheExtent: 400, ...)
  • 发现页itemBuilder 返回 RepaintBoundary(child: _WorkCard(...))GridView.builder(..., cacheExtent: 400, ...)
  • 收藏页itemBuilder 返回 RepaintBoundary(child: ListTile(...))ListView.builder(..., cacheExtent: 400, ...)

小结

通过 在 ImageCacheService 支持 abandonFuture 并在 NetworkImageWidget 的 dispose/URL 变更时 complete 对应 Completer,避免列表快速滑动时已 dispose 的组件继续参与异步回调;通过为首页、发现页、收藏页的列表项根节点包一层 RepaintBoundary,将重绘隔离在单格内;通过为上述 GridView/ListView 设置 cacheExtent: 400,提前构建即将进入视口的 item,减少滚动等待感。三项均属中低优先级优化,可与既有图片缓存、解析优化等配合使用。

结束语

感谢阅读本帖,如对贴中内容有意见和建议的,欢迎与我联系交流,也欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐