如何拦截Flutter的Image.network调用,优先加载本地存储图片?
自定义ImageProvider实现本地优先加载方案
完全可以实现这个需求,核心思路是不直接拦截Image.network,而是自定义一个支持本地优先逻辑的ImageProvider,替代默认的NetworkImage,就能在图片加载流程里加入本地存储检查。
具体实现步骤
- 自定义LocalFirstImageProvider
继承Flutter的ImageProvider,在加载逻辑里先查询SQLite数据库,判断对应URL的本地图片是否存在:
- 如果存在,直接加载本地文件;
- 如果不存在,再发起网络请求。
示例代码:
class LocalFirstImageProvider extends ImageProvider<LocalFirstImageProvider> { final String url; final Database db; LocalFirstImageProvider(this.url, this.db); @override Future<LocalFirstImageProvider> obtainKey(ImageConfiguration configuration) { return SynchronousFuture(this); } @override ImageStreamCompleter loadImage(LocalFirstImageProvider key, ImageDecoderCallback decode) { return MultiFrameImageStreamCompleter( codec: _loadCodec(key, decode), scale: 1.0, informationCollector: () => [ DiagnosticsProperty<ImageProvider>('Provider', this), DiagnosticsProperty<String>('Target URL', url), ], ); } Future<Codec> _loadCodec(LocalFirstImageProvider key, ImageDecoderCallback decode) async { // 第一步:查询SQLite获取本地路径 final localPath = await _queryLocalPath(key.url); if (localPath != null) { final file = File(localPath); if (await file.exists()) { // 加载本地图片 final bytes = await file.readAsBytes(); return decode(await ImmutableBuffer.fromUint8List(bytes)); } } // 第二步:本地无缓存,走网络加载 final networkProvider = NetworkImage(url); final networkKey = await networkProvider.obtainKey(ImageConfiguration.empty); return networkProvider.loadImage(networkKey, decode); } Future<String?> _queryLocalPath(String url) async { // 替换成你的SQLite查询逻辑 final result = await db.query( 'user_images', // 假设存储图片路径的表名 where: 'remote_url = ?', whereArgs: [url], ); return result.isNotEmpty ? result.first['local_path'] as String : null; } @override bool operator ==(Object other) => identical(this, other) || other is LocalFirstImageProvider && other.url == url; @override int get hashCode => url.hashCode; }
- 替换Image.network的使用方式
直接在需要加载图片的地方,用自定义的Provider替代默认的NetworkImage:
// 假设你已经初始化了SQLite数据库实例db Image( image: LocalFirstImageProvider('https://your-image-url.com/test.jpg', db), fit: BoxFit.cover, )
优化建议
- 把SQLite操作封装成单例工具类,避免每次传递db实例;
- 加入内存缓存,缓存已查询过的URL和本地路径映射,减少重复数据库查询;
- 处理本地文件损坏的情况:如果本地文件存在但解码失败,自动 fallback 到网络加载;
- 兼容
Image.network的参数(比如headers、scale),可以在自定义Provider里添加对应参数,传递给内部的NetworkImage。
内容的提问来源于stack exchange,提问作者Ajay Kumar
相关产品推荐
相关产品推荐

