没有网络(开飞行模式)也提示下载成功?Flutter cached_network_image 图片加载流程分析

本文分析了Flutter中cached_network_image库在无网络连接时仍能显示图片的原因,解释了图片加载、缓存的流程,以及如何在无网络情况下提示下载成功。cached_network_image依赖flutter_cache_manager库进行图片的下载和缓存,使用Database和本地文件系统存储,即使在飞行模式下,图片已被缓存故能成功显示。
摘要由CSDN通过智能技术生成

前言

为什么没有网络(开飞行模式)也弹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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值