我分析图片加载流程,不是直接从Image这个类开始分析的。我现拿 cached_network_image ^3.2.3这个图片缓存框架进行解析。其实cached_network_image这个框架本质上还是处理Image类的,往下看就知道了,只是cached_network_image这个框架对他进行的一些封装,加了原生没有的文件缓存功能。
图片处理机制流程
- 注册图片流数据监听
- 从网络获取图片数据,并进行图片缓存
- 对图片数据进行解码
- 返回图片解码数据,最终绘制图片
一、注册图片流数据监听
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 的作用包括以下几个方面:
-
加载图像数据:ImageProvider 提供了 resolve 方法,用于加载图像数据。根据具体的子类实现,它可以从本地文件、网络地址、内存缓存或其他来源获取图像数据。
-
图像缓存管理:ImageProvider 通常与图像缓存一起工作,以提高图像加载性能。它可以使用缓存来避免重复加载相同的图像数据,提高图像的加载速度和效率。
-
图像大小和缩放处理:ImageProvider 可以提供图像的大小信息,以便 Image widget 可以正确布局和显示图像。它还可以根据 Image widget 的要求进行图像的缩放和裁剪,以适应不同的显示需求。
-
错误处理和备用图像:如果图像加载过程中发生错误,ImageProvider 提供了错误处理机制。它可以通知使用 Image widget 的代码,以便显示备用图像或执行其他错误处理逻辑。
-
图像加载状态管理: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。它负责以下几个任务:
-
发起图像加载:ImageStreamCompleter 会根据提供的图像资源路径或网络地址等信息,发起图像加载请求。
-
图像解码:一旦图像数据被下载完成,ImageStreamCompleter 会负责将图像数据解码为可用的位图数据。
-
图像缩放和裁剪:在解码完成后&