重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
打开 pubspec.yaml 文件,找到 assets: 开头的Key,将其注释放开并配置正确路径
目前创新互联建站已为1000多家的企业提供了网站建设、域名、网络空间、网站托管、企业网站设计、宁海网站维护等服务,公司将坚持客户导向、应用为本的策略,正道将秉承"和谐、参与、激情"的文化,与客户和合作伙伴齐心协力一起成长,共同发展。
一. flutter中我们想加载本地图片,需要两步:
二. flutter项目中本地图片加载的原理
在加载图片时,系统自动会根据屏幕分辨率优先选择到符合自己分配率的文件夹(2.0x或者3.0x或者4.0x)下去取相对应的图片,如果当前文件夹下没有,则会到低一倍的文件夹下去,如果还没有,则继续向更低一倍去取。(比如:iOS 5.5英寸及以上屏幕会优先选择去3.0x下去取图片,如果3.0x不存在或者3.0x文件夹下没有,则去2.0x下取;如果2.0x不存在或者2.0x下没有,则去1.0x下取;1.0x下再没有,则在images文件下取)。
其中,参数 image 类型为抽象类 ImageProvider ,定义了图片数据获取和加载的相关接口。
根据不同的数据来源,派生出不同的 ImageProvider :
抽象类 ImageProvider 提供了一个用于加载数据源的抽象方法 @protected ImageStreamCompleter load(T key, DecoderCallback decode); 接口,不同的数据源定义各自的实现。
子类 NetworkImage 实现如下:
load 方法返回类型为抽象类 ImageStreamCompleter ,其中定义了一些管理图片加载过程的接口,比如 addListener 、 removeListener 、 addOnLastListenerRemovedCallback 等, MultiFrameImageStreamCompleter 为其子类。
MultiFrameImageStreamCompleter 第一个参数 codec 类型为 Futureui.Codec ,用来对突破进行解码,当 codec 准备好的时候,就会立即对图片第一帧进行解码操作。
codec 为 _loadAsync 方法返回值,
_loadAsync 方法实现:
decode 方法的类型:
其中解码传入的回调方法 image_provider.DecoderCallback decode ,
传入 Uint8List ,返回 Futureui.Codec 。
而对 decode 回调方法的具体定义,在 ImageProvider 的 resolveStreamForKey 方法中做了定义, resolveStreamForKey 方法在 ImageProvider 的 resolve 方法中有调用, resolve 方法则为 ImageProvider 类层级结构的公共入口点。
resolveStreamForKey 和 resolve 实现如下:
decode 方法,即 PaintingBinding.instance!.instantiateImageCodec ,即为具体图片解码的方法实现。
ui.instantiateImageCodec 实现:
descriptor.instantiateCodec 方法实现:
_instantiateCodec 方法的实现,最终到了 native 的实现:
其中返回值类型 Codec 里定义了一些属性:
obtainKey 方法:
ImageProvider 定义了一个抽象方法 FutureT obtainKey(ImageConfiguration configuration); ,供子类来实现,其中 NetworkImage 的实现为:
obtainKey 作用:
配合实现图片缓存, ImageProvider 从数据源加载完数据后,会在 ImageCache 中缓存图片数据,图片数据缓存时一个 Map ,其中 Map 中的 key 便是 obtainKey 。
resolve 作为 ImageProvider 提供给 Image 的主入口方法,参数为 ImageConfiguration ,
resolve 其中调用了 _createErrorHandlerAndKey 方法,设置了成功回调和失败回调:
其中 _createErrorHandlerAndKey 方法的实现,便调用了 obtainKey 来设置 key 。
在成功回调里,调用了方法 resolveStreamForKey ,里面有具体的缓存实现 PaintingBinding.instance!.imageCache!.putIfAbsent :
PaintingBinding.instance!.imageCache 是ImageCache的一个实例,是 PaintingBinding 的一个属性,是一个单例,图片缓存是全局的。
如上述判断:
ImageCache 定义:
ImageCache 缓存池:
在 NetworkImage 中,对 ImageProvider 的抽象方法 obtainKey 进行了实现,将自己创建了一个同步 Future 进行返回:
同时,自身又重写了 ImageProvider 定义的 == 比较操作符,通过图片 url 和图片的缩放比例 scale 进行比较:
通过ImageCache提供的方法来设置:
Flutter的图片缓存机制有问题(可能是我使用的版本1.12.13有问题)
网络图片会默认缓存到本地,但是不管图片是不是完整的或者损坏的,导致页面在下次进入的时候会优先从缓存里读取图片。有些图片是没有加载完成的,或者损坏的,导致图片无法显示。UI效果就是显示成白色的。
一种解决方式:加载前或者退出后清理图片缓存
ImageCache imageCache = PaintingBinding.instance.imageCache;
imageCache.clear();
缺点就是每次图片都想要从网络上获取,增加服务器负担