图片加载原理与缓存
在本书前面章节已经介绍过Image 组件,并提到Flutter框架对加载过的图片是有缓存的(内存),默认最大缓存数量是1000,最大缓存空间为100M。本节便详细介绍Image的原理及图片缓存机制,下面我们先看看ImageProvider 类。
14.5.1 ImageProvider
我们已经知道Image 组件的image 参数是一个必选参数,它是ImageProvider类型。下面我们便详细介绍一下ImageProvider,ImageProvider是一个抽象类,定义了图片数据获取和加载的相关接口。它的主要职责有两个:
- 提供图片数据源
- 缓存图片
我们看看ImageProvider抽象类的详细定义:
abstract class ImageProvider<T> {
ImageStream resolve(ImageConfiguration configuration) {
// 实现代码省略
}
Future<bool> evict({ ImageCache cache,
ImageConfiguration configuration = ImageConfiguration.empty }) async {
// 实现代码省略
}
Future<T> obtainKey(ImageConfiguration configuration);
@protected
ImageStreamCompleter load(T key); // 需子类实现
}
load(T key)方法
加载图片数据源的接口,不同的数据源的加载方法不同,每个ImageProvider的子类必须实现它。比如NetworkImage类和AssetImage类,它们都是ImageProvider的子类,但它们需要从不同的数据源来加载图片数据:NetworkImage是从网络来加载图片数据,而AssetImage则是从最终的应用包里来加载(加载打到应用安装包里的资源图片)。 我们以NetworkImage为例,看看其load方法的实现:
@override
ImageStreamCompleter load(image_provider.NetworkImage key) {
final StreamController<ImageChunkEvent> chunkEvents = StreamController<ImageChunkEvent>();
return MultiFrameImageStreamCompleter(
codec: _loadAsync(key, chunkEvents), //调用
chunkEvents: chunkEvents.stream,
scale: key.scale,
... //省略无关代码
);
}
我们看到,load方法的返回值类型是ImageStreamCompleter ,它是一个抽象类,定义了管理图片加载过程的一些接口,Image Widget中正是通过它来监听图片加载状态的(我们将在下面介绍Image 原理时详细介绍)。
MultiFrameImageStreamCompleter 是 ImageStreamCompleter的一个子类,是flutter sdk预置的类,通过该类,我们以方便、轻松地创建出一个ImageStreamCompleter实例来做为load方法的返回值。
我们可以看到,MultiFrameImageStreamCompleter 需要一个codec参数,该参数类型为Future<ui.Codec>。Codec 是处理图片编解码的类的一个handler,实际上,它只是一个flutter engine API 的包装类,也就是说图片的编解码逻辑不是在Dart 代码部分实现,而是在flutter engine中实现的。Codec类部分定义如下:
@pragma('vm:entry-point')
class Codec extends NativeFieldWrapperClass2 {
// 此类由flutter engine创建,不应该手动实例化此类或直接继承此类。
@pragma('vm:entry-point')
Codec._();
/// 图片中的帧数(动态图会有多帧)
int get frameCount native 'Codec_frameCount';
/// 动画重复的次数
/// * 0 表示只执行一次
/// * -1 表示循环执行
int get repetitionCount native 'Codec_repetitionCount';
/// 获取下一个动画帧
Future<FrameInfo> getNextFrame() {
return _futurize(_getNextFrame);
}
String _getNextFrame(_Callback<FrameInfo> callback) native 'Codec_getNextFrame';
我们可以看到Codec最终的结果是一个或多个(动图)帧,而这些帧最终会绘制到屏幕上。
MultiFrameImageStreamCompleter 的 codec参数值为_loadAsync方法的返回值,我们继续看_loadAsync方法的实现:
Future<ui.Codec> _loadAsync(
NetworkImage key,
StreamController<ImageChunkEvent> chunkEvents,
) asyn

本文深入探讨Flutter的ImageProvider和Image组件的工作原理,包括ImageProvider如何加载和缓存图片,以及Image组件如何与ImageProvider协作显示图片。通过源码分析,揭示了Flutter图片加载的内存缓存策略,指出缓存发生在内存中,不涉及本地持久化,并讨论了缓存的key生成逻辑。
最低0.47元/天 解锁文章
5591

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



