Code前端首页关于Code前端联系我们

Flutter 10完整进化详解:深入图像加载流程

terry 2年前 (2023-09-23) 阅读数 63 #移动小程序

在Flutter中,图像加载主要由Image控件和

  • 控件实现。本身就是 StatefulWidget ,从上一篇文章我们很快就能想到 Image 一定对应它的 ❀❀❀❀❀❀ layout 和 油漆,那么这个过程中图像是如何转换成屏幕并显示出来的呢? ? ,首先 Image 获取 ImageStream 对象
  • 2 -

    2 - Ima,然后 我_ImageState使用

    2 ImageStream 添加监控,等待图像数据

  • 3,然后ImageProvider使用loadloadload方法amgege
    • 对象
    • 4。然后 ImageStream 绑定到 ImageStreamCompleter
    • 5,然后通过 ImageStreamCompleter 然后 PaintingBinding 编码转换得到ui.Codec绘图.对象并封装ImageInfo返回

      回调ImageStream的显示,设置为_ImageState 结构 RawImage来自对象。

    • 7。最后,在ImageInfo♽❀中用颜料绘制RawImage / RenderImage。 ui.Codec

    注意,这是 ui.Codec以及后面的ui.Imageui.Image等只是为了在导入时区分Flutter类型和其他类型而添加对象:将'dart:ui'作为UI表示编解码器;

    你头晕了吗?放松!后面我们会慢慢了解这个过程。 Flutter完整开发实战详解十:深入图片加载流程

    Flutter的图片加载过程主要有三个作用:

    • Image:用于显示图片的Widget,最后绘制内部utin❝。 ? 、AssetImage 等以获取 ImageStream 用于跟踪 ❝❀ 结果。
    • ImageStream:图片上传对象ImageStreamCompleter最终返回ImageInfo和 geInfo包含Render的图片 最后一个 绘制对象 ui.Image

    如上整体镜像流程所示,网络镜像是通过这个Provider加载NetworkImage。不同Provider的实现确实很大。大同小异,其中最重要的实现方法主要如下图所示:Flutter完整开发实战详解十:深入图片加载流程

    1。 getKey

    该方法主要用于标记当前Provider是否存在。例如,在 NetworkImage 中,返回的方法是 SynchronousFuture(this)♼,即❀♼,即,并且使用生成的密钥 ImageProvider ♼ 缓存键值为。

    NetworkImage 主要是runtimeType

    、l、 l scale

    这三个参数定义了两个NetworkImage。等于 ,因此,除了url之外,图像的比例也会影响缓存的对象。

    2。 load(T key)

    load方法,顾名思义就是加载,而这个方法中使用的key无疑是从上面的obtainKey方法中获取到的。

    load方法返回ImageStreamCompleter抽象对象,主要使用 ❀ dart:ui.Image 例如,NetworkImage。 MultiFrameImageStreamCompleter 的子类,可以处理多帧动画。如果图像中只有一针,则执行一次并完成。

    3。解决

    ImageProvider的关键在于resolve方法。从流程图中我们知道该方法为 Image 生命周期调用方法中 didChangeDependencies ,

    , ♻, te

    reassemble

    被调用。在下面的源代码中可以看到,这里调用了obtainKeyloadFlutter完整开发实战详解十:深入图片加载流程

    这里有一个有趣的对象,那就是❝♶❝!

    因为在Flutter中,同步异常可以用try-catch捕获,而像Future这样的异步异常无法直接在当前try-catch中捕获。

    所以在Dart的Zone概念中,你可以给执行对象分配一个Zone,这类似于沙箱环境,你可以在沙箱内部提供这个。 all 可以捕获、捕获或修改某些代码行为,例如所有未处理的异常。

    resolve方法主要使用PaintingBinding.instance.imageCache.putIfAbsent(key, () => load(key)in 是一个胶水类,主要用在 WidgetsFlutterBinding. 通过 Mixins. 正如我们在上一章中所说, WidgetsFlutterBinding 是我们的启动方法❙

    因此,图像缓存作为单个实例保留在 PaintingBinding.instance.imageCache 中。

    如下图所示,putIfAbsent在方法内部,主要是在内存中进行评估。对象是否已经缓存或者已经缓存,如果是,则返回ImageStreamCompleter ,否则请致电loader

    值得注意的是,缓存目前有两种状态,因为返回的 ImageStreamCompleter并不意味着图像已经加载完毕,所以如果是第一次加载, 会先出现。 I_PendingImage 用于指向 key 的图像处于 加载状态,并添加 ListenerFlutter完整开发实战详解十:深入图片加载流程

    不对,这里的缓存概念和我们理解的有点不一样。之前,通常会缓存关键位图对象,也就是实际的绘图数据,而Flutter 只缓存 ImageStreamCompleter

    对象,而不是实际的绘图对象 dart:ui.Image 。 ? dart:ui.Image

    对象 ImageInfo。

    接下来我们看ImageStreamCompleter实现类MultiFrameImageStreamCompleterMa。如下代码所示,MultiFrameImageStreamCompleter主要通过codec参数获取渲染数据,该数据源是从_ssync获取的。 方法,主要通过http获取图像上传后,通过PaintingBinding对图像数据进行编码,将图像转换为机器绘制的数据。Flutter完整开发实战详解十:深入图片加载流程

    内部MultiFrameImageStreamCompleterui.Codec来自

    通过ImageInfo 对其进行封装,并逐渐回调回_ImageState。 ,然后将数据传递给RenderImage - setState♽进行绘制。 Flutter完整开发实战详解十:深入图片加载流程

    那又怎么样?现在回顾一下一开始的流程图。是不是感觉一切都清楚了?

    2。本地图片缓存

    了解了上面的流程,我们知道Flutter实现了内存中图片缓存,但没有实现本地图片缓存,所以我们的出发点应该是从ImageProvider开始。

    根据上面对NetworkImage的分析,我们知道图片是通过http通过_loadAsync

    _loadAsync方法加载的,所以我们加载 NetworkImage 简历 复制代码,编辑_loadAsync,支持加载前读取http本地缓存,加载后将数据存储在本地。

    结合flutter_cache_manager插件,如下代码所示,可以快速轻松地启用本地图片缓存:

     Future<ui.Codec> _loadAsync(NetworkImage key) async {
        assert(key == this);
    
        /// add this start
        /// flutter_cache_manager DefaultCacheManager
        final fileInfo = await DefaultCacheManager().getFileFromCache(key.url);
        if(fileInfo != null && fileInfo.file != null) {
          final Uint8List cacheBytes = await fileInfo.file.readAsBytes();
          if (cacheBytes != null) {
            return PaintingBinding.instance.instantiateImageCodec(cacheBytes);
          }
        }
        /// add this end
    
        final Uri resolved = Uri.base.resolve(key.url);
        final HttpClientRequest request = await _httpClient.getUrl(resolved);
        headers?.forEach((String name, String value) {
          request.headers.add(name, value);
        });
        final HttpClientResponse response = await request.close();
        if (response.statusCode != HttpStatus.ok)
          throw Exception('HTTP request failed, statusCode: ${response?.statusCode}, $resolved');
    
        final Uint8List bytes = await consolidateHttpClientResponseBytes(response);
        if (bytes.lengthInBytes == 0)
          throw Exception('NetworkImage is an empty file: $resolved');
        
        /// add this start
        await DefaultCacheManager().putFile(key.url, bytes);
        /// add this edn
    
        return PaintingBinding.instance.instantiateImageCodec(bytes);
      }
    复制代码

    3.其他插件。缓存量

    关于闲鱼 Flutter Web 应用内存分析文章详细分析了图片加载导致的内存问题,其中之一就是ImageCache 问题。

    我们知道上面的流程,ImageCache缓存了一个异步对象。缓存异步加载对象的一个​​问题是,在图像加载和解码之前你无法知道会消耗多少内存,并且大量图像的加载会导致解码任务产生大量 IO。

    在Flutter中ImageCache默认缓存大小为

    const int _kDefaultSize = 1000;
    const int _kDefaultSizeBytes = 100 << 20; // 100 
    复制代码

    所以简单粗暴的做法是:tingb.simage.inchem.inchem。 ;

    同时页面出现时不暂停加载图片等。

    2、.9 图像

    在图像中,您可以通过centerSlice 设置参数设置 .9 图像效果。

    自此,第十章终于结束了! (///▽///)

    作者:连毛德小果
    链接:https://juejin.im/post/5cb1896ce51d456e63760449‽来源:♓❓❓‿s版权归作者所有。商业转载请联系作者获得许可。非商业转载请注明出处。

  • 版权声明

    本文仅代表作者观点,不代表Code前端网立场。
    本文系作者Code前端网发表,如需转载,请注明页面地址。

    发表评论:

    ◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

    热门