前言
为什么没有网络(开飞行模式)也弹Toast提示下载成功?
下意识反应,肯定是Toast提示弹早了,刚点击按钮,还没开始下载就弹了Toast,赶紧拿手机过来操作验证一波。确实没有网络,弹了下载完成提示,去相册检查一下,嗯?图片下载成功了,还有这种操作?赶紧检查一下代码,发现项目中使用的cached_network_image三方库加载的图片,从名字上可以判断,这是一个缓存网络图片的加载框架。所以应该是图片显示出来以后就被缓存到本地了,实际下载的流程并未走网络请求,为了验证想法,看了下框架加载图片流程,总结出下文。
使用
组件CachedNetworkImage可以支持直接使用或者通过ImageProvider。
引入依赖
dependencies:
cached_network_image: ^3.1.0
执行flutter pub get,项目中使用
Import it
import 'package:cached_network_image/cached_network_image.dart';
添加占位图
CachedNetworkImage(
imageUrl: "http://via.placeholder.com/350x150",
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
),
进度条展示
CachedNetworkImage(
imageUrl: "http://via.placeholder.com/350x150",
progressIndicatorBuilder: (context, url, downloadProgress) =>
CircularProgressIndicator(value: downloadProgress.progress),
errorWidget: (context, url, error) => Icon(Icons.error),
),
原生组件Image配合
Image(image: CachedNetworkImageProvider(url))
使用占位图并提供provider给其他组件使用
CachedNetworkImage(
imageUrl: "http://via.placeholder.com/200x150",
imageBuilder: (context, imageProvider) => Container(
decoration: BoxDecoration(
image: DecorationImage(
image: imageProvider,
fit: BoxFit.cover,
colorFilter:
ColorFilter.mode(Colors.red, BlendMode.colorBurn)),
),
),
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
),
这样就可以加载网络图片了,而且,图片加载完成时,就被缓存到本地了,首先看下图片的加载流程
官网说了,它现在不包含缓存,缓存功能实际上是另一个库flutter_cache_manager中实现的
原理
加载&显示
这里我们仅梳理图片加载和缓存的主流程,对于一些其他分支流程,或无关参数不做过多分析
首先,页面上使用的构造函数接收了一个必传参数imageUrl,用于生成ImageProvider提供图片加载
class CachedNetworkImage extends StatelessWidget{
/// image提供
final CachedNetworkImageProvider _image;
/// 构造函数
CachedNetworkImage({
Key key,
@required this.imageUrl,
/// 省略部分
this.cacheManager,
/// ...
}) : assert(imageUrl != null),
/// ...
_image = CachedNetworkImageProvider(
imageUrl,
headers: httpHeaders,
cacheManager: cacheManager,
cacheKey: cacheKey,
imageRenderMethodForWeb: imageRenderMethodForWeb,
maxWidth: maxWidthDiskCache,
maxHeight: maxHeightDiskCache,
),
super(key: key);
@override
Widget build(BuildContext context) {
var octoPlaceholderBuilder =
placeholder != null ? _octoPlaceholderBuilder : null;
var octoProgressIndicatorBuilder =
progressIndicatorBuilder != null ? _octoProgressIndicatorBuilder : null;
/// ...
return OctoImage(
image: _image,
/// ...
);
}
}
这里可以看到,构造函数初始化了一个本地变量_image 类型是CachedNetworkImageProvider,它继承ImageProvider提供图片加载,看下它的构造函数
/// 提供网络图片加载Provider并缓存
abstract class CachedNetworkImageProvider
extends ImageProvider<CachedNetworkImageProvider> {
/// Creates an object that fetches the image at the given URL.
const factory CachedNetworkImageProvider(
String url, {
int maxHeight,
int maxWidth,
String cacheKey,
double scale,
@Deprecated('ErrorListener is deprecated, use listeners on the imagestream')
ErrorListener errorListener,
Map<String, String> headers,
BaseCacheManager cacheManager,
ImageRenderMethodForWeb imageRenderMethodForWeb,
}) = image_provider.CachedNetworkImageProvider;
/// 可选cacheManager. 默认使用 DefaultCacheManager()
/// 当运行在web时,cacheManager没有使用.
BaseCacheManager get cacheManager;
/// 请求url.
String get url;
/// 缓存key
String get cacheKey;
/// ...
@override
ImageStreamCompleter load(
CachedNetworkImageProvider ke