05 resolve
ImageProvider
的关键在于 resolve
方法,从流程图我们可知,该方法在 Image
的生命周期回调方法 didChangeDependencies
、 didUpdateWidget
、 reassemble
里会被调用,从下方源码可以看出,上面我们所实现的 obtainKey
和 load
都会在这里被调用
这个有个有意思的对象,就是
Zone
!因为在 Flutter 中,同步异常可以通过try-catch捕获,而异步异常如
Future
,是无法被当前的 try-catch 直接捕获的。所以在 Dart中
Zone
的概念,你可以给执行对象指定一个Zone
,类似提供一个沙箱环境,而在这个沙箱内,你就可以全部可以捕获、拦截或修改一些代码行为,比如所有未被处理的异常。
resolve
方法内主要是用到了 PaintingBinding.instance.imageCache.putIfAbsent(key, () => load(key)
, PaintingBinding
是一个胶水类,主要是通过 Mixins 粘在 WidgetsFlutterBinding
上使用,而以前的篇章我们说过, WidgetsFlutterBinding
就是我们的启动方法 runApp
的执行者。
所以图片缓存是在PaintingBinding.instance.imageCache内单例维护的。
如下图所示,putIfAbsent
方法内部,主要是通过 key
判断内存中是否已有缓存、或者正在缓存的对象,如果是就返回该 ImageStreamCompleter
,不然就调用 loader
去加载并返回。
值得注意的是,此时的的 cache 是有两个状态的,因为返回的 ImageStreamCompleter
并不代表着图片就加载完成,所以如果是首次加载,会先有 _PendingImage
用于标示该key的图片处于加载中的状态 ,并且添加一个 listener
, 用于图片加载完成后,替换为缓存 _CacheImage
。
发现没有,这里和我们理解上的 Cache 概念稍微有点不同,以前我们缓存的一般是 key - bitmap 对象,也就是实际绘制数据,而在 Flutter 中,缓存的仅是ImageStreamCompleter
对象,而不是实际绘制对象 dart:ui.Image
。
学员评价