Flutter开发中记录一个非常好用的图片缓存清理的插件

发布于:2025-06-27 ⋅ 阅读:(18) ⋅ 点赞:(0)

在flutter开发中,当App项目内存吃紧时,页面中如果图片很多时需要及时清理,如果不能及时清理,会造成内存泄漏,导致App卡顿甚至强制退出或手机死机。

这里我使用extended_image封装了一个全局可用的Widget,亲测IOS和安卓好用。

首先在pubspec.yaml文件中配置插件并下载,执行Pub get。
 

dependencies:
  extended_image: ^6.2.0

我使用的是6.2.0版本,基于ExtendedImage我对netWork网络图片组件做了如下封装,内有注释与备注,就不做过多的解释了,完全都能看的懂!

class JudgeNetworkImage extends StatefulWidget {
  const JudgeNetworkImage(
    this.url, {
    Key? key,
    this.width,
    this.height,
    this.isAvatar = false,
    this.fit = BoxFit.cover,
    this.borderRadius,
    this.shape,
    this.borderWidth = 0.0,
    this.borderColor,
    this.opacity = 1.0,
    this.scale = 1.0,
    this.maxBytes,
    this.filterQuality = FilterQuality.low,
    this.repeat = ImageRepeat.noRepeat,
    this.replaceImgPlayback = false,
    this.enableMemoryCache = true,
    this.clearMemoryCacheIfFailed = true,
    this.clearMemoryCacheWhenDispose = true,
    this.cacheRawData = false,
    this.placeholder,
    this.errorWidget,
    this.loadingWidget,
    this.defaultImagePath,
  }) : super(key: key);

  final String url; // 图片URL
  final double? width; // 宽度
  final double? height; // 高度
  final bool isAvatar; // 是否为头像
  final BoxFit fit; // 适配方式
  final BorderRadius? borderRadius; // 圆角
  final BoxShape? shape; // 形状(圆形/矩形)
  final double borderWidth; // 边框宽度
  final Color? borderColor; // 边框颜色
  final double opacity; // 透明度
  final double scale; // 缩放比例
  final int? maxBytes; // 控制图片加载时的字节大小限制
  final FilterQuality filterQuality; // 缩放质量
  final ImageRepeat repeat; // 重复方式
  final bool replaceImgPlayback; // 更换图片时是否保留旧图
  final bool enableMemoryCache; // 启用内存缓存
  final bool clearMemoryCacheIfFailed; // 加载失败时清除缓存
  final bool clearMemoryCacheWhenDispose; // 组件销毁时清除缓存
  final bool cacheRawData; // 缓存原始数据
  final Widget? placeholder; // 加载中占位图
  final Widget? errorWidget; // 加载失败组件
  final Widget? loadingWidget; // 加载中组件
  final String? defaultImagePath; // 默认图片路径

  @override
  State<JudgeNetworkImage> createState() => _JudgeNetworkImageState();
}

class _JudgeNetworkImageState extends State<JudgeNetworkImage> {
  late String _url;

  @override
  void initState() {
    super.initState();
    _url = widget.url;
  }

  @override
  void dispose() {
    super.dispose();
    if (widget.clearMemoryCacheWhenDispose) {
      // 主动清除图片缓存
      if (_url.isNotEmpty && _url != (widget.defaultImagePath ?? '')) {
        final provider = ExtendedNetworkImageProvider(_url);
        provider.evict();
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    Widget child = Container(
      width: widget.width ?? double.maxFinite,
      height: widget.height ?? double.maxFinite,
      decoration: BoxDecoration(
        // 边框部分
        border: widget.borderWidth > 0
            ? Border.all(
                color: widget.borderColor ?? Colors.transparent,
                width: widget.borderWidth,
              )
            : null,
      ),
      child: ExtendedImage.network(
        _url,
        width: widget.width,
        height: widget.height,
        fit: widget.fit,
        scale: widget.scale,
        filterQuality: widget.filterQuality,
        repeat: widget.repeat,
        gaplessPlayback: widget.replaceImgPlayback,
        enableMemoryCache: widget.enableMemoryCache,
        clearMemoryCacheIfFailed: widget.clearMemoryCacheIfFailed,
        clearMemoryCacheWhenDispose: widget.clearMemoryCacheWhenDispose,
        cacheRawData: widget.cacheRawData,
        maxBytes: widget.maxBytes,
        // 应用透时度
        color: widget.opacity < 1.0
            ? Colors.white.withOpacity(widget.opacity)
            : null,
        colorBlendMode: widget.opacity < 1.0 ? BlendMode.srcIn : null,
        clipBehavior: Clip.none,
        // 加载状态回调
        loadStateChanged: (state) {
          return _handleLoadState(state);
        },
      ),
    );

    if (widget.shape == BoxShape.circle) {
      return ClipOval(
        child: child,
      );
    } else if (widget.borderRadius != null) {
      return ClipRRect(
        borderRadius: widget.borderRadius,
        child: child,
      );
    } else {
      return child;
    }
  }

  /// 处理加载状态
  Widget _handleLoadState(ExtendedImageState state) {
    switch (state.extendedImageLoadState) {
      case LoadState.loading:
        // 加载中显示指示器
        return SizedBox(
          width: widget.width != null ? widget.width! * 0.4 : 42.rpx,
          child: Center(
            child: CircularProgressIndicator(
              valueColor:
                  const AlwaysStoppedAnimation<Color>(AppColors.success),
              strokeWidth: 4.rpx,
            ),
          ),
        );
      case LoadState.completed:
        return state.completedWidget;
      case LoadState.failed:
        // 加载失败 - 显示默认图片并清除缓存
        _clearCacheOnError(state);
        return Container(
          color: const Color(0xFFF2F2F2),
          alignment: Alignment.center,
          child: widget.isAvatar
              ? Image.asset(
                  '${AppGlobal.imgUrl}man_presuppose.png',
                  fit: BoxFit.fill,
                )
              : Image.asset(
                  '${AppGlobal.imgUrl}not_pic.png',
                  width: widget.width != null ? widget.width! * 0.6 : 64.rpx,
                  fit: BoxFit.fitWidth,
                ),
        );
    }
  }

  void _clearCacheOnError(ExtendedImageState state) {
    if (widget.clearMemoryCacheIfFailed && mounted) {
      // 获取图片提供者并清除缓存
      if (state.imageProvider is ExtendedNetworkImageProvider) {
        final provider = state.imageProvider as ExtendedNetworkImageProvider;
        provider.evict();
      }
    }
  }
}

以上就是一个完整的网络图片widget的封装,对性能提升有相当大的帮助!


网站公告

今日签到

点亮在社区的每一天
去签到