Flutter本地图片缓存
缓存工具类源码
解决的问题是:加载本地图片,但是依旧会卡顿一下显示的问题。在项目的启动阶段调用(主要是在显示图片之前的那个界面调用)。
调用与源码
import 'package:flutter/widgets.dart';
import 'package:myapp/app/utils/logger/logger.dart';
import 'package:myapp/gen/assets.gen.dart';
class LocalImageCache {
/// 缓存 Flutter Gen 自动生成的所有图片
static Future<void> precacheAll(BuildContext context) async {
// 所有需要缓存的图片路径
final images = <AssetGenImage>[
Assets.images.login.headBgLg,
Assets.images.question.headBackground,
Assets.images.booking.rightJiantou,
Assets.images.booking.yuzuHead,
Assets.images.booking.paizhao,
Assets.images.yuding.headWoshou,
Assets.images.question.headBackground,
Assets.images.login.loginPhoneWhite,
Assets.images.login.cryIconLg,
Assets.images.xgmm.mail,
Assets.images.xgmm.suo,
Assets.images.xgmm.cha,
Assets.images.xgmm.mail,
Assets.images.xgmm.cha,
Assets.images.people.banIcon,
Assets.images.people.yuzuIcon,
Assets.images.xingge.xingge,
Assets.images.pingjia.juziA,
Assets.images.pingjia.juziB,
Assets.images.pingjia.juziC,
Assets.images.pingjia.juziD,
Assets.images.pingjia.juziE,
Assets.images.pingjia.juziF,
Assets.images.pingjia.juziWoshou,
Assets.images.pingjia.message,
Assets.images.pingjia.juziList,
Assets.images.pingjia.juziKong,
Assets.images.pingjia.juzi,
Assets.images.home.homeDark,
Assets.images.home.homeLight,
Assets.images.home.messageDark,
Assets.images.home.messageLight,
Assets.images.home.peopleDark,
Assets.images.home.peopleLight,
];
for (final img in images) {
await precacheImage(img.image().image, context);
}
logger.d("✅ 所有本地图片预缓存完成");
}
/// 清除所有图片缓存(内存缓存 + 未使用缓存)
static void clearAll() {
final cache = PaintingBinding.instance.imageCache;
cache.clear(); // 清空所有缓存
cache.clearLiveImages(); // 再清空未使用的缓存
logger.d("🗑️ 所有本地图片缓存已清除");
}
/// 清除指定图片缓存
static void clearOne(AssetGenImage img) {
final provider = img.image().image;
PaintingBinding.instance.imageCache.evict(provider);
logger.d("🗑️ 图片缓存已清除: ${img.path}");
}
}
能命中缓存 的调用方式例子(假设你已经在 LocalImageCache.precacheAll(context) 里缓存了 Assets.images.home.homeDark):
✅ 会命中缓存的几种写法
方式一:直接用 AssetGenImage.image()
Assets.images.home.homeDark.image(
width: 24,
height: 24,
);
这是最标准的,和预缓存时的
img.image().image一致。
方式二:用 Image.asset,路径相同
Image.asset(
'assets/images/home/home_dark.png',
width: 24,
height: 24,
);
生成的
AssetImage('assets/images/home/home_dark.png')和预缓存的AssetImage一致,所以能命中缓存。
方式三:手动创建同一个 AssetImage
const AssetImage assetImg = AssetImage('assets/images/home/home_dark.png');
Image(
image: assetImg,
width: 24,
height: 24,
);
这里
assetImg和Assets.images.home.homeDark.image().image是相同的AssetImage,所以也能用缓存。
⚠️ 不会命中缓存的几种情况
-
解码参数不一样
// 预缓存时用 24x24 Assets.images.home.homeDark.image(width: 24, height: 24); // 使用时换成 48x48 Assets.images.home.homeDark.image(width: 48, height: 48);Flutter 会认为这是不同的
ImageProvider,重新解码。 -
不同 bundle
Image.asset( 'assets/images/home/home_dark.png', bundle: rootBundle, // 和默认 bundle 不一样 );bundle 不同,无法命中。
-
缓存被清理 如果缓存数量或大小超过
PaintingBinding.instance.imageCache的限制,旧图片会被回收,再次使用会重新解码。
👉 总结一下:
- 只要路径和 bundle 一致,就能命中缓存。
- 大小(
width/height)不同会导致不一致。 - 最推荐的方式就是始终用
Assets.images.xxx.image()保持一致。