Flutter 中提供了Widget 组件供开发者解决日常中关于图片相关的需求,其中包含 Image.file() 读取用户内存中图片,Image.asset() 加载程序包含的图片资源,Image.network() 用于网络图片的加载,我们主要通过 Image 对于网络图片加载的实现来初步了解 Image 组件的原理。
首先从构造函数开始:
Image.network(
String src, {
Key? key,
double scale = 1.0,
...
}) : image = ResizeImage.resizeIfNeeded(cacheWidth, cacheHeight, NetworkImage(src, scale: scale, headers: headers)),
...
super(key: key);
/// The image to display.
final ImageProvider image;
其中在构造Image对象时,最重要的变量 image,是一个ImageProvider 对象,从名字可以看出他是图片的提供者,ImageProvider 是一个抽象类,子类包括 NetworkImage,FileImage,AssetImage,MemoryImage等,稍后我们细说NetworkImage,继续看 Image 组件的实现。
Image 作为一个 StatefulWidget 他的状态由 _ImageState 控制,从生命周期的执行顺序看下来
@override
void didChangeDependencies() {
_updateInvertColors();
_resolveImage();
if (TickerMode.of(context))
_listenToStream();
else
_stopListeningToStream(keepStreamAlive: true);
super.didChangeDependencies();
}
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,
));
assert(newStream != null);
_updateSourceStream(newStream);
}
函数通过调用 imageProvider 的 resolve 方法创建 ImageStream 对象,该对象是一个图片资源的句柄,它持有图片资源加载完毕后的监听回调和图片资源的管理者,而后续介绍到其中的 ImageStreamCompleter 对象是图片资源的一个管理类; resolve 方法是 ImageProvider 暴露给 Image 组件的主入口方法,接受一个图片相关的配置对象,返回对应的 ImageStream 图片数据流,我们深入查看 NetwokImage 的 resolve 实现。
@nonVirtual
ImageStream resolve(ImageConfiguration configuration) {
assert(configuration != null);
final ImageStream stream = createStream(configuration);
// 加载key(可能是异步的),设置错误处理zone,然后调用 resolveStreamForKey。
_createErrorHandlerAndKey(
configuration,
(T key, ImageErrorListener errorHandler) {
resolveStreamForKey(configuration, stream, key, errorHandler);
},
(T? key, Object exception, StackTrace? stack) async {
...
},
);
return stream;
}
void _createErrorHandlerAndKey(
ImageConfiguration configuration,
_KeyAndErrorHandlerCallback<T> successCallback,
_AsyncKeyErrorHandler<T?> errorCallback,
) {
T? obtainedKey;
bool didError = false;
Future<void> handleError(Object exception, StackTrace? stack) async {
...
}
// 创建一个新Zone,主要是为了当发生错误时不会干扰MainZone
final Zone dangerZone = Zone.current.fork(...);
dangerZone.runGuarded(() {
Future<T> key;
try {
// 生成缓存key,后面会根据此key来检测是否有缓存
key = obtainKey(configuration);
} catch (error, stackTrace) {
handleError(error, stackTrace);
return;
}
key.then<void>((T key) {
obtainedKey = key;
try {
// 成功回调
successCallback(key, hand

本文详细解析了Flutter中Image组件与ImageProvider的工作原理,特别是NetworkImage的加载流程,包括图片下载、解码、缓存管理和错误处理。重点介绍了ImageStream、ImageStreamCompleter和如何利用key进行图片缓存控制。

2466

被折叠的 条评论
为什么被折叠?



