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

Flutter cached_network_image 在 OpenHarmony 上的图片缓存实践与问题排查

前言

最近在做 Flutter for OpenHarmony 项目时,图片加载这块确实踩了不少坑。

项目里有很多:

  • 商品封面
  • Banner
  • 用户头像
  • 长图详情页

一开始直接用的是:


Image.network()

开发阶段看起来没什么问题。

但真正放到鸿蒙设备上跑一段时间后,问题慢慢就出来了:

  • 图片闪烁
  • 滑动列表掉帧
  • 图片重复加载
  • 页面偶发白屏
  • 弱网下体验很差

尤其是列表快速滑动的时候,体验会明显下降。

后面我把项目里的网络图片全部切换成了 cached_network_image,同时又针对 OpenHarmony 做了一些额外优化,整体效果稳定了很多。

这篇文章主要记录一下这次图片缓存优化过程。


一、为什么不建议直接用 Image.network

先看最基础的写法。


Image.network(imageUrl)

Flutter 官方确实提供了这个组件。

但在实际项目里:

它更适合:

  • demo
  • 小项目
  • 图片数量少的页面

如果页面图片很多,问题会逐渐明显。


我遇到的几个问题

1. 图片重复请求

列表上下滑动后:

同一张图片会再次请求。

尤其在 OpenHarmony 上:

频繁请求会明显影响流畅度。


2. 图片加载闪烁

页面切换时:

图片会出现短暂空白。

体验会比较差。


3. 弱网场景体验差

如果网络不好:

整个列表会疯狂转圈。

没有占位图的话:

页面会显得特别乱。


二、接入 cached_network_image

后面我改成了:


dependencies:
  cached_network_image: ^3.3.1

然后执行:


flutter pub get

三、基础使用方式

替换代码其实很简单。


原来的写法


Image.network(
  imageUrl,
  fit: BoxFit.cover,
)

替换后


CachedNetworkImage(
  imageUrl: imageUrl,
  fit: BoxFit.cover,
)

仅这一层替换:

就已经能减少很多重复加载问题。


四、一定要加 placeholder

这是我后面总结出来很重要的一点。


不加占位图的问题

如果图片加载稍慢:

页面会先显示空白。

尤其 OpenHarmony 真机里:

这种闪烁会比较明显。


推荐写法


CachedNetworkImage(
  imageUrl: imageUrl,

  placeholder: (context, url) {
    return Container(
      height: 100,
      alignment: Alignment.center,
      child: const CircularProgressIndicator(),
    );
  },

  fit: BoxFit.cover,
)

这样用户至少知道:

页面正在加载。


五、错误占位图也很重要

这个问题我是在测试环境里发现的。

因为测试接口偶尔会返回失效图片。

结果页面直接出现:


Exception caught by image resource service

而且有些图片区域会直接空掉。


后来的处理方式


CachedNetworkImage(
  imageUrl: imageUrl,

  errorWidget: (context, url, error) {
    return const Icon(
      Icons.image_not_supported,
    );
  },
)

这样即使图片失败:

页面布局也不会乱。


六、OpenHarmony 下的一个实际问题

这里有个我在鸿蒙设备上真实遇到的问题。


问题现象

页面第一次打开:

图片正常。

切后台再回来:

部分图片偶发不显示。

但:

  • Android 正常
  • iOS 正常

只有 OpenHarmony 比较容易复现。


排查过程

一开始我怀疑:

  • 网络权限
  • 图片格式
  • 缓存路径

后面查了很久发现:

问题主要还是图片组件 rebuild 太频繁。


最后的优化方案

我给列表 Item 增加了:


const

同时:

避免父组件频繁 setState。

例如:


const GoodsItem()

优化后:

图片白屏问题明显减少。


七、列表场景一定要控制图片尺寸

这个问题很多人容易忽略。


错误写法


CachedNetworkImage(
  imageUrl: imageUrl,
)

如果不限制尺寸:

Flutter 会动态计算布局。

大量图片时:

GPU 压力会明显增加。


推荐写法


SizedBox(
  width: 120,
  height: 120,

  child: CachedNetworkImage(
    imageUrl: imageUrl,
    fit: BoxFit.cover,
  ),
)

在 OpenHarmony 真机上:

流畅度会好很多。


八、长列表里的图片优化

商品列表是我这次优化里问题最多的部分。


问题

列表快速滑动时:

会出现:

  • 图片加载跟不上
  • 页面掉帧
  • 滚动卡顿

后来的处理

1. ListView.builder


ListView.builder(
  itemBuilder: (_, index) {
    return GoodsItem();
  },
)

避免一次性创建大量图片组件。


2. 减少 rebuild

我把:

  • 点赞状态
  • 收藏状态
  • 价格变化

单独拆成局部 Widget。

避免整个 Item 重建。


3. RepaintBoundary

复杂 Item:


RepaintBoundary(
  child: GoodsItem(),
)

这个优化在鸿蒙设备上效果挺明显。


九、缓存清理问题

这个是后面项目上线后遇到的。


问题现象

长时间使用后:

缓存越来越大。

部分低端设备:

会开始出现:

  • 页面变慢
  • 图片加载延迟

解决方案

我后来增加了缓存清理。


await DefaultCacheManager().emptyCache();

例如:

  • 退出登录
  • 清理缓存按钮

时主动执行。


十、弱网环境测试

这个我建议一定要做。

因为 OpenHarmony 真机在弱网环境下:

图片体验会比 Android 更容易暴露问题。


我测试的方法

直接限制网络:

  • 3G
  • 弱 WiFi
  • 高延迟

然后观察:

  • 图片闪烁
  • 页面布局
  • 滑动流畅度

最终优化结果

优化前:

问题 表现
图片闪烁 明显
图片白屏 偶发
列表掉帧 存在
重复请求 高频

优化后:

项目 效果
图片缓存 稳定
页面流畅度 提升明显
图片失败处理 更完善
弱网体验 更稳定

十一、总结

这次做 Flutter for OpenHarmony 图片优化,一个比较深的感受是:

图片问题很多时候不只是“图片组件”的问题。

真正影响体验的:

其实是:

  • Widget rebuild
  • 列表结构
  • 图片尺寸
  • 缓存策略
  • 页面刷新机制

cached_network_image 确实帮我解决了不少问题。

但如果页面结构本身不合理:

即使加缓存,效果也有限。

目前我项目里已经基本统一:

  • 网络图片全部缓存
  • 统一 placeholder
  • 统一 errorWidget
  • 长列表全部懒加载

整体体验已经稳定很多。

后面我还准备继续研究:

  • Flutter 图片预加载
  • OpenHarmony 图片缓存目录
  • WebP 在鸿蒙下的性能
  • 大图长图优化方案

希望这篇文章能给正在做 Flutter for OpenHarmony 开发的同学一点参考。

Logo

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

更多推荐