Flutter 扒一扒图片缓存框架cached_network_image

本文以cached_network_image ^3.2.3图片缓存框架为例,分析Flutter图片加载流程。包括注册图片流数据监听,介绍ImageProvider和ImageStreamCompleter作用;从网络获取图片数据并做文件缓存;对图片数据进行解码;最终绘制图片,将解析完的数据传入RawImage类渲染。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我分析图片加载流程,不是直接从Image这个类开始分析的。我现拿 cached_network_image ^3.2.3这个图片缓存框架进行解析。其实cached_network_image这个框架本质上还是处理Image类的,往下看就知道了,只是cached_network_image这个框架对他进行的一些封装,加了原生没有的文件缓存功能。

图片处理机制流程

  1. 注册图片流数据监听
  2. 从网络获取图片数据,并进行图片缓存
  3. 对图片数据进行解码
  4. 返回图片解码数据,最终绘制图片

一、注册图片流数据监听


CachedNetworkImage类

 Widget build(BuildContext context) {
    return OctoImage(
         image: _image,
         imageBuilder: imageBuilder != null ? _octoImageBuilder : null,
         placeholderBuilder: octoPlaceholderBuilder,
         progressIndicatorBuilder: octoProgressIndicatorBuilder,
         errorBuilder: errorWidget != null ? _octoErrorBuilder : null,
         fadeOutDuration: fadeOutDuration,
         fadeOutCurve: fadeOutCurve,
         fadeInDuration: fadeInDuration,
         fadeInCurve: fadeInCurve,
         width: width,
         height: height,
         fit: fit,
         alignment: alignment,
         repeat: repeat,
         matchTextDirection: matchTextDirection,
         color: color,
         filterQuality: filterQuality,
         colorBlendMode: colorBlendMode,
         placeholderFadeInDuration: placeholderFadeInDuration,
         gaplessPlayback: useOldImageOnUrlChange,
         memCacheWidth: memCacheWidth,
         memCacheHeight: memCacheHeight,
       );
  }

我们看到CachedNetworkImage的build的方法返回的是OctoImage,看来CachedNetworkImage就是个马甲,我们继续进入OctoImage类看看。

我们看到了OctoImage类调用了 _imageHandler.build(context),看来OctoImage也是个马甲,最终的实现看来是在ImageHandler类里了

ImageHandler类

    Widget build(BuildContext context) {
      return Image(
        key: ValueKey(image),
        image: image,
        loadingBuilder: imageLoadingBuilder(),
        frameBuilder: imageFrameBuilder(),
        errorBuilder: errorWidgetBuilder(),
        fit: fit,
        width: width,
        height: height,
        alignment: alignment,
        repeat: repeat,
        color: color,
        colorBlendMode: colorBlendMode,
        matchTextDirection: matchTextDirection,
        filterQuality: filterQuality,
      );
    }
   

从上面的代码来看,ImageHandler也是个马甲,最终还是调用framework类里Image类。

那我们来看看Image类做了什么
在didChangeDependencies方法中,我们看到了一个比较重要的方法_resolveImage();

 void _resolveImage() {
    final ScrollAwareImageProvider provider = ScrollAwareImageProvider<Object>(
      context: _scrollAwareContext,
      imageProvider: widget.image,
    );
    final ImageStream newStream =
      provider.resolve(createLocalImageConfiguration(
        context,
        size: widget.width != null && widget.height != null ? Size(widget.width!, widget.height!) : null,
      ));
    _updateSourceStream(newStream);
  }

  void _updateSourceStream(ImageStream newStream) {
    if (_imageStream?.key == newStream.key) {
      return;
    }

    if (_isListeningToStream) {
      _imageStream!.removeListener(_getListener());
    }

    if (!widget.gaplessPlayback) {
      setState(() { _replaceImage(info: null); });
    }

    setState(() {
      _loadingProgress = null;
      _frameNumber = null;
      _wasSynchronouslyLoaded = false;
    });

    _imageStream = newStream;
    if (_isListeningToStream) {
      _imageStream!.addListener(_getListener());
    }
  }


  ImageStreamListener _getListener({bool recreateListener = false}) {
      if (_imageStreamListener == null || recreateListener) {
        _lastException = null;
        _lastStack = null;
        _imageStreamListener = ImageStreamListener(
          _handleImageFrame,
          onChunk: widget.loadingBuilder == null ? null : _handleImageChunk,
          onError: widget.errorBuilder != null || kDebugMode
              ? (Object error, StackTrace? stackTrace) {
                  setState(() {
                    _lastException = error;
                    _lastStack = stackTrace;
                  });

                    return true;
                  }());
                }
              : null,
        );
      }
      return _imageStreamListener!;
    }

从源码可以看出_resolveImage方法主要做的是

将ImageProvider 和 ImageStream产生了关联。然后注册一个图片流监听事件
就是ImageStreamListener这个类。当图片数据获取到之后就会通过监听回调,然后setState将图片渲染出来。

在 Flutter 中,ImageProvider 是一个抽象类,定义了加载图像所需的方法和属性。它的主要作用是为 Image widget 提供图像数据。

ImageProvider 的作用包括以下几个方面:

  1. 加载图像数据:ImageProvider 提供了 resolve 方法,用于加载图像数据。根据具体的子类实现,它可以从本地文件、网络地址、内存缓存或其他来源获取图像数据。

  2. 图像缓存管理:ImageProvider 通常与图像缓存一起工作,以提高图像加载性能。它可以使用缓存来避免重复加载相同的图像数据,提高图像的加载速度和效率。

  3. 图像大小和缩放处理:ImageProvider 可以提供图像的大小信息,以便 Image widget 可以正确布局和显示图像。它还可以根据 Image widget 的要求进行图像的缩放和裁剪,以适应不同的显示需求。

  4. 错误处理和备用图像:如果图像加载过程中发生错误,ImageProvider 提供了错误处理机制。它可以通知使用 Image widget 的代码,以便显示备用图像或执行其他错误处理逻辑。

  5. 图像加载状态管理:ImageProvider 负责跟踪图像加载的状态,并通知 Image widget 更新其显示状态。它可以告知 Image widget 图像的加载进度,从而实现加载中、加载完成等不同的状态展示。

通过使用不同的 ImageProvider 子类,可以从不同的来源加载图像,如网络图像、本地文件、内存等。ImageProvider 的具体子类包括 AssetImage、NetworkImage、FileImage 等,每个子类都提供了特定的图像加载方式和参数。

总之,ImageProvider 是 Image widget 的数据提供者,负责加载、缓存和管理图像数据,并与 Image widget 协同工作,确保图像正确地显示在应用程序中。

ImageStreamCompleter 的作用包括以下几个方面:
在 Flutter 中,ImageStreamCompleter 是用于处理图像加载和解码的重要组件。它是 ImageProvider 的一部分,负责管理图像的加载、解码和处理过程。

当您在 Flutter 中使用 Image widget 来显示图像时,Image widget 内部会使用 ImageProvider 来获取图像数据。而 ImageProvider 则使用 ImageStreamCompleter 来管理图像的加载和解码。

ImageStreamCompleter 的主要作用是监听图像加载过程中的各个阶段,并在加载完成后通知 ImageProvider。它负责以下几个任务:

  1. 发起图像加载:ImageStreamCompleter 会根据提供的图像资源路径或网络地址等信息,发起图像加载请求。

  2. 图像解码:一旦图像数据被下载完成,ImageStreamCompleter 会负责将图像数据解码为可用的位图数据。

  3. 图像缩放和裁剪:在解码完成后&

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值