【开源鸿蒙跨平台开发先锋训练营】Flutter实现鸿蒙App性能优化(内存与生命)实战
检查了下项目中存在的性能优化,故做了如下调整。
欢迎加入开源鸿蒙跨平台社区: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 第四部分「内存与生命周期」。

二、思路
- 2.1:在
ImageCacheService.getImage中增加可选参数abandonFuture(Future<void>);组件在请求时传入一个Completer<void>.future,在dispose或 URL 变更时completer.complete(),使该次等待立即结束并返回 null,不阻塞已 dispose 的组件;不取消底层 Dio 请求,其他等待同一 URL 的调用仍可拿到结果。 - 2.2:在首页(PageView 单页、GridView 格子)、发现页(卡片)、收藏页(ListTile)的每个 item 根节点外包一层
RepaintBoundary。 - 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 根节点包 RepaintBoundary;GridView.builder 设置 cacheExtent: 400。 |
lib/pages/search_page.dart |
itemBuilder 中每个 _WorkCard 外包 RepaintBoundary;GridView.builder 设置 cacheExtent: 400。 |
lib/pages/favorites_page.dart |
itemBuilder 中每个 ListTile 外包 RepaintBoundary;ListView.builder 设置 cacheExtent: 400。 |
无新增 pub 依赖;使用 Dart 标准库 dart:async 的 Completer。
四、实现要点
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();请求返回后除_disposed、mounted外再判断_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)
- 状态与 dispose:
Completer<void>? _abandonCompleter;_loadImage()内新建Completer并传入getImage(..., abandonFuture: _abandonCompleter!.future);返回后if (_disposed || !mounted || _abandonCompleter!.isCompleted) return;dispose()中_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
更多推荐



所有评论(0)