Flutter中的网络请求图片存储为缓存,与定制删除本地缓存 ...

打印 上一主题 下一主题

主题 826|帖子 826|积分 2478

Flutter中的网络请求图片存储为缓存,与定制删除本地缓存
1:封装请求图片函数
2:访问的图片都会转为本地缓存,当相同的请求url,会在本地调用图片
3:本地缓存管理【windows与andriod已经测试】【有页面】【有调用案例】
4:删除本地缓存
清理缓存页面(下方代码中已包括)


windows中显示图片-----------安卓中显示图片
这里还没有进行优化图片显示的宽高,圆角,请自行设置

打印日志(显示图片请求的获取过程与报错原因)


TuPianJiaZai 图片加载工具使用教程

注意事项


  • imageUrl 可以为 null,此时会显示空白
  • 图片会自动缓存到本地
  • 支持自动重试3次
  • 默认有加载动画和错误提示
  • 支持所有尺度图片格式
现实应用场景


  • 商品展示卡片
  • 用户头像
  • 图片列表
  • 背景图片
  • Banner图片
1. 基本用法

1.1导入文件
  1. import '../utils/get_images/tupianjiazai.dart';
复制代码
  1. TuPianJiaZai.jiazaiTupian(
  2.                           imageUrl: product.image,
  3.                           width: double.infinity,
  4.                           height: 200,
  5.                           fit: BoxFit.cover,
  6. )
复制代码
2. 完整参数说明

  1. TuPianJiaZai.jiazaiTupian(
  2.                          // 必需参数
  3.                         imageUrl: String?, // 图片URL,可以为null
  4.                         // 可选参数
  5.                         width: double?, // 显示宽度
  6.                         height: double?, // 显示高度
  7.                         fit: BoxFit, // 图片填充方式,默认BoxFit.cover
  8.                         cacheWidth: int?, // 缓存图片宽度,用于优化内存
  9.                         cacheHeight: int?, // 缓存图片高度,用于优化内存
  10.                         placeholder: Widget?, // 加载时显示的占位Widget
  11.                         errorWidget: Widget?, // 加载失败时显示的Widget
  12. )
复制代码
3. 使用案例

3.1 基础加载

  1. TuPianJiaZai.jiazaiTupian(
  2.                         imageUrl: 'https://example.com/image.jpg',
  3.                         width: 200,
  4.                         height: 200,
  5. )
复制代码
3.2 自定义占位图和错误图

  1. TuPianJiaZai.jiazaiTupian(
  2.                         imageUrl: imageUrl,
  3.                         width: 300,
  4.                         height: 200,
  5.                         placeholder: const Center(
  6.                         child: CircularProgressIndicator(),
  7.                         ),
  8. errorWidget: const Center(
  9.                         child: Column(
  10.                                         mainAxisAlignment: MainAxisAlignment.center,
  11.                                         children: [Icon(Icons.error),Text('加载失败'),],
  12.                                     ),
  13.                        ),
  14. )
复制代码
3.3 列表项中使用

  1. ListView.builder(
  2. itemBuilder: (context, index) {
  3. return TuPianJiaZai.jiazaiTupian(
  4. imageUrl: imageUrls[index],
  5. height: 150,
  6. fit: BoxFit.cover,
  7. cacheWidth: 600, // 优化缓存大小
  8. cacheHeight: 400,
  9. );
  10. },
  11. )
复制代码
请自行在\lib\utils\get_images\文件夹中创建一下设置

D:\F\luichun\lib\utils\get_images\huancunguanli.dart
  1. import 'dart:io';
  2. import 'dart:typed_data';
  3. import 'package:path_provider/path_provider.dart';
  4. import 'package:crypto/crypto.dart';
  5. import 'dart:convert';
  6. import 'package:shared_preferences/shared_preferences.dart';
  7. import 'package:synchronized/synchronized.dart';
  8. import 'logger.dart';  // 使用统一的日志管理器
  9. import '../env_config.dart';// 本地进行开发时,使用 会对 localhost:10005 进行请求,但是安卓模拟器需要把localhost转换为 10.0.2.2
  10. /// 完整工作流程:
  11. /// 1.应用启动 -> 初始化缓存目录
  12. /// 2.请求图片 -> 检查缓存 -> 返回缓存或null
  13. /// 3.下载图片 -> 保存图片 -> 更新映射关系
  14. /// 4.定期维护 -> 清理缓存/计算大小
  15. /// 图片缓存管理器
  16. /// 用于管理图片的本地缓存,减少重复的网络请求
  17. class HuanCunGuanLi {
  18.   /// 单例模式
  19.   ///   使用工厂构造函数确保全局只有一个缓存管理器实例
  20.   ///   避免重复创建缓存目录和资源浪费
  21.   static final HuanCunGuanLi _instance = HuanCunGuanLi._internal();
  22.   
  23.   /// 缓存目录
  24.   Directory? _cacheDir;
  25.   
  26.   /// 初始化锁
  27.   final _lock = Lock();
  28.   
  29.   /// 初始化标志
  30.   bool _isInitialized = false;
  31.   
  32.   /// 持久化存储的键名
  33.   static const String _prefKey = 'image_cache_urls';
  34.   
  35.   // 工厂构造函数
  36.   factory HuanCunGuanLi() {
  37.     return _instance;
  38.   }
  39.   // 私有构造函数
  40.   HuanCunGuanLi._internal();
  41.   /// 确保已初始化
  42.   Future<void> _ensureInitialized() async {
  43.     if (_isInitialized) return;  // 快速检查
  44.    
  45.     await _lock.synchronized(() async {
  46.       if (_isInitialized) return;  // 双重检查
  47.       await init();
  48.     });
  49.   }
  50.   /// 初始化缓存目录
  51.   Future<void> init() async {
  52.     try {
  53.       final appDir = await getApplicationDocumentsDirectory();
  54.       final cacheDir = Directory('${appDir.path}/image_cache');
  55.       
  56.       if (!await cacheDir.exists()) {
  57.         await cacheDir.create(recursive: true);
  58.       }
  59.       
  60.       _cacheDir = cacheDir;
  61.       _isInitialized = true;
  62.       
  63.       if (EnvConfig.isDevelopment) {
  64.         ImageLogger.logCacheInfo('缓存系统初始化完成: ${_cacheDir!.path}');
  65.       }
  66.     } catch (e) {
  67.       ImageLogger.logCacheError('缓存系统初始化失败', error: e);
  68.       rethrow;
  69.     }
  70.   }
  71.   /// 3异步获取缓存图片
  72.   /// 参数:
  73.   ///   url: 图片的网络地址
  74.   /// 返回:
  75.   ///   Uint8List?: 图片的二进制数据,不存在时返回null
  76.   /// 流程:
  77.   ///   1. 根据URL生成缓存键
  78.   ///   2. 查找本地缓存文件
  79.   ///   3. 返回缓存数据或null
  80.   Future<Uint8List?> huoquTupian(String url) async {
  81.     await _ensureInitialized();
  82.     try {
  83.       final cacheKey = _shengchengKey(url);
  84.       final cacheFile = File('${_cacheDir!.path}/$cacheKey');
  85.       
  86.       if (await cacheFile.exists()) {
  87.         ImageLogger.logCacheDebug('从缓存加载图片', {'url': url});
  88.         return await cacheFile.readAsBytes();
  89.       }
  90.       return null;
  91.     } catch (e) {
  92.       ImageLogger.logCacheError('读取缓存图片失败', error: e);
  93.       return null;
  94.     }
  95.   }
  96.   /// 异步保存图片到缓存
  97.   /// [url] 图片URL
  98.   /// [imageBytes] 图片二进制数据
  99.   Future<void> baocunTupian(String url, Uint8List imageBytes) async {
  100.     await _ensureInitialized();
  101.     final cacheKey = _shengchengKey(url);
  102.     final cacheFile = File('${_cacheDir!.path}/$cacheKey');
  103.     await cacheFile.writeAsBytes(imageBytes);
  104.     await _baocunURLyingshe(url, cacheKey);
  105.   }
  106.   /// 生成缓存键
  107.   /// 使用MD5加密URL生成唯一标识
  108.   String _shengchengKey(String url) {
  109.     final bytes = utf8.encode(url);
  110.     final digest = md5.convert(bytes);
  111.     return digest.toString();
  112.   }
  113.   /// 4. URL 映射管理:
  114.   /// 保存URL映射关系
  115.   /// 实现:
  116.   ///   1. 获取SharedPreferences实例
  117.   ///   2. 读取现有映射
  118.   ///   3. 更新映射关系
  119.   ///   4. 序列化并保存
  120.   ///   使用 SharedPreferences 持久化存储 URL 映射关系
  121.   ///   JSON 序列化保存映射数据
  122.   ///   异步操作避免阻塞主线程
  123.   /// 保存URL映射关系
  124.   Future<void> _baocunURLyingshe(String url, String cacheKey) async {
  125.     final prefs = await SharedPreferences.getInstance();
  126.     final Map<String, String> urlMap = await _huoquURLyingshe();
  127.     urlMap[url] = cacheKey;
  128.     await prefs.setString(_prefKey, jsonEncode(urlMap));
  129.   }
  130.   /// 获取URL映射关系
  131.   Future<Map<String, String>> _huoquURLyingshe() async {
  132.     final prefs = await SharedPreferences.getInstance();
  133.     final String? mapJson = prefs.getString(_prefKey);
  134.     if (mapJson != null) {
  135.       return Map<String, String>.from(jsonDecode(mapJson));
  136.     }
  137.     return {};
  138.   }
  139.   /// 5.缓存清理功能:
  140.   /// 清除所有缓存
  141.   /// 使用场景:
  142.   ///   1. 应用清理存储空间
  143.   ///   2. 图片资源更新
  144.   ///   3. 缓存出现问题时重置
  145.   /// 递归删除缓存目录
  146.   /// 清除 URL 映射数据
  147.   /// 清除所有缓存
  148.   Future<void> qingchuHuancun() async {
  149.     await _cacheDir!.delete(recursive: true);
  150.     await _cacheDir!.create();
  151.     final prefs = await SharedPreferences.getInstance();
  152.     await prefs.remove(_prefKey);
  153.   }
  154.    ///6 .缓存大小计算:
  155.    ///- 异步遍历缓存目录
  156.    /// 累计所有文件大小
  157.    /// 使用 Stream 处理大目录
  158.   /// 获取缓存大小(字节)
  159.   Future<int> huoquHuancunDaxiao() async {
  160.     int size = 0;
  161.     await for (final file in _cacheDir!.list()) {
  162.       if (file is File) {
  163.         size += await file.length();
  164.       }
  165.     }
  166.     return size;
  167.   }
  168. }
复制代码
D:\F\luichun\lib\utils\get_images\logger.dart
[code]import 'package:logger/logger.dart';

/// 图片加载系统的日志管理器
class ImageLogger {
  static final Logger _logger = Logger(
    printer: PrettyPrinter(
      methodCount: 0,
      errorMethodCount: 8,
      lineLength: 120,
      colors: true,
      printEmojis: true,
      dateTimeFormat: DateTimeFormat.onlyTimeAndSinceStart,
    ),
  );

  // 缓存系统日志
  static void logCacheInfo(String message) {
    _logger.i('

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

海哥

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表