Flutter图片加载原理与缓存

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

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

图片加载原理与缓存

在本书前面章节已经介绍过Image 组件,并提到Flutter框架对加载过的图片是有缓存的(内存),默认最大缓存数量是1000,最大缓存空间为100M。本节便详细介绍Image的原理及图片缓存机制,下面我们先看看ImageProvider 类。

14.5.1 ImageProvider

我们已经知道Image 组件的image 参数是一个必选参数,它是ImageProvider类型。下面我们便详细介绍一下ImageProviderImageProvider是一个抽象类,定义了图片数据获取和加载的相关接口。它的主要职责有两个:

  1. 提供图片数据源
  2. 缓存图片

我们看看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 原理时详细介绍)。

MultiFrameImageStreamCompleterImageStreamCompleter的一个子类,是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,
    StreamCont
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值