作者:闲鱼技能——新宿

布景:

去年,闲鱼新一代图片库 PowerImage 在经过一系列灰度、问题修正、代码调优后,已全量稳定应用于闲鱼。相关于上一代 IFImage,PowerIma数组的定义ge 经过进一步的演进,适应了更多的事务场景与最新的 flutter 特性,处理了一系列痛点:比方,因为彻底抛弃了原生的swift语言 ImageCache,在与原生图片混用的场景下,会让一些低频的图片反而占用了缓存;比方,咱们在模拟器上无法展现图片;比方咱们在相册中,需求在图片库之外再搭建图片通道。swiftly

简介:

PowerImage 是一个充分利用 native 原生图片库才能、高扩展性的flutflutteredter图片库。咱们奇妙架构是什么意思地将外接纹路与 ffi 计划组合,以更靠近fluttershy原生的规划,处理了一系列事务痛点。

才能特点:

  • • 支撑加载 ui.Image 才能。在根据外接纹路的计划中,运用方无法拿到真实的 ui架构图怎么画.Image 去运用,这导致图片库在这种特殊的运用场景下力不从心。
  • • 支撑图片预加载才能。正如原生precacheImage一样。这在某些对图片展现速度要求较高的场景下十数组分有用。
  • • 新增纹路缓存,与原生图片库缓存打通!一致图片缓存缓存,防止原生图片混用带来的内存问题。
  • • 支撑模拟器。在 fluSwifttter-1.23.0-18.1.p数组c语言re之前的版别,模拟器无法展现 Texture Widget。
  • 缓存视频合并app 完善自定义图片类型通道。处理事务自定义图片获取缓存的视频在哪诉求。
  • • 完善的反常捕获与收集。
  • • 支撑动图。(来fluttering自淘特的PR)

Flutter 原生计划:

在介绍新计划开端fluttering之前,先简单回想一下 flutter 原生图片计划。

节日献礼:Flutter图片库重磅开源!

原生 Image Widget 先经过 ImageProvider 得到 ImageStream,经过监听它的数组词状况,进行各种状况的展现。比方frameBuilderloadingBuilder,最终在图片加载flutter面试题成功后,会 rebuildRawImageRawImage 会经过 RenderImage 来制作,整个制作的中心是 ImageInfo 中的 ui.Image

  • • Image:担flutter面试题任图片加载的各个状况的展现,如加载中、失败、加载成功展现图片等。
  • • ImageProvider:担任 ImageStream 的获取,比方体系内置的 NetworkImage、AssetImage 等。
  • • ImageSt缓存视频在手机哪里找ream:图片资源加载的目标数组指针

在整理 flutter 原生图片计划之后,咱们发现是不是有机会在某个环节将 flutter 图片和 native 以原生的方法打通?flutter面试题

新一代计划:

咱们奇妙地将 FFi 计划与外接纹路计划组合,处理了一系列事务痛点。

FFI:

正如开头说的那些问题,Tflutter框架exture 计划有些做不到的工作,这需求其他计划来互补,这其中中心需求的便是 ui.Image。咱们把 native 内存地址、长度等信息传递给 flutter 侧,用于生成 ui.Image

首先 native 侧先获取必要的参数(以 iOS 为例):

    _rowBytes = CGImageGetBytesPerRow(cgImage);        CGDataProviderRef dataProvider = CGImageGetDataProvider(cgImage);    CFDataRef rawDataRef = CGDataProviderCopyData(dataProvider);    _handle = (long)CFDataGetBytePtr(rawDataRef);        NSData *data = CFBridgingRelease(rawDataRef);    self.data = data;    _length = data.length;

dart 侧拿到后

@override  FutureOr<ImageInfo> createImageInfo(Map map) {    Completer<ImageInfo> completer = Completer<ImageInfo>();    int handle = map['handle'];    int length = map['length'];    int width = map['width'];    int height = map['height'];    int rowBytes = map['rowBytes'];    ui.PixelFormat pixelFormat =        ui.PixelFormat.values[map['flutterPixelFormat'] ?? 0];    Pointer<Uint8> pointer = Pointer<Uint8>.fromAddress(handle);    Uint8List pixels = pointer.asTypedList(length);    ui.decodeImageFromPixels(pixels, width, height, pixelFormat,        (ui.Image image) {      ImageInfo imageInfo = ImageInfo(image: image);      completer.complete(imageInfo);      //开释 native 内存      PowerImageLoader.instance.releaseImageRequest(options);    }, rowBytes: rowBytes);    return completer.future;  }

咱们能够经过 ffi 拿到 naflutter面试题tive 内存,然后生成 ui.Image。这里有个问swift是什么组织缩写题,虽然经过 ffi 能直接获取 native 内存,架构师和程序员的区别但是架构因为 decodeImageFromPixels 会有内存复制,在复制解码后的图片数据时,内存峰值会swift代码愈加严峻。

这里有两个优化方向:

  1. 1. 解码前的图片数据给flutter是什么意思 flutter,由 flutter 供给的解码器解码,然后削减内存复制峰值。
  2. 2. 与 flutter 官方讨论,测验从内部削减这次内存复制。

FFI 这种方法适架构师和程序员的区别合轻度运用、特殊场景运用,支撑这种方法能够处理无法获取 ui.Image 的问题,也能缓存文件夹名称够在模拟器上展现图片(flutterswift系统 &架构图lt;= 1.23.0-18.1.p缓存视频合并re),而且图片缓存将彻底交给 ImageCache 办理。缓存清理

Texture:

Texture 计划与原生结合有缓存的视频在哪一些难度,这里涉及到没有 ui.Image 只要 textu数组和链表的区别reId。这里有几个问题需求处理:

问题一:Image Widget 需求 ui.Image 去 build RawImage 然后制作,这在本文前面的Flutter 原生计划介绍中也提到了。 问题二:ImageCache 依赖 ImageInfo 中 ui.Image架构师证书宽高进行 cache 巨细核算以及缓存前的校验。 问题三:native 侧 texture 生命周期flutter框架办理swift代码

都有处理计划:

问题一:经过自定义 Image 处理,透出fluttershy imageBuilder 来让外部自定义图片 widget 问题二:为数组词 Texture架构师证书 自定义 ui.image,如下:

import 'dart:typed_data';import 'dart:ui' as ui show Image;import 'dart:ui';class TextureImage implements ui.Image {  int _width;  int _height;  int textureId;  TextureImage(this.textureId, int width, int height)      : _width = width,        _height = height;  @override  void dispose() {    // TODO: implement dispose  }  @override  int get height => _height;  @override  Future<ByteData> toByteData(      {ImageByteFormat format = ImageByteFormat.rawRgba}) {    // TODO: implement toByteData    throw UnimplementedError();  }  @override  int get width => _width;}

这样的话,TextureImage 实际上便是个壳,仅仅用来核算 cache 巨缓存英文细。 实际上,ImageCache 核算巨细,彻底没必要直接接触到 ui.架构图怎么画Image,能够直接找 ImageInfo 取,这样的话就没有这个问题了swifter。这个问题数组指针能够详细看 @皓黯 的 ISSUE 与 PR。

问题三:关于 native 侧感知 flutter image 开释机遇的问题

修正的 ImageCache 开释如下(部分代码):

typedef void HasRemovedCallback(dynamic key, dynamic value);class RemoveAwareMap<K, V> implements Map<K, V> {  HasRemovedCallback hasRemovedCallback;  ...}//------  final RemoveAwareMap<Object, _PendingImage> _pendingImages = RemoveAwareMap<Object, _PendingImage>();//------void hasImageRemovedCallback(dynamic key, dynamic value) {    if (key is ImageProviderExt) {      waitingToBeCheckedKeys.add(key);    }    if (isScheduledImageStatusCheck) return;    isScheduledImageStatusCheck = true;    //We should do check in MicroTask to avoid if image is remove and add right away    scheduleMicrotask(() {      waitingToBeCheckedKeys.forEach((key) {        if (!_pendingImages.containsKey(key) &&            !_cache.containsKey(key) &&            !_liveImages.containsKey(key)) {          if (key is ImageProviderExt) {            key.dispose();          }        }      });      waitingToBeCheckedKeys.clear();      isScheduledImageStatusCheck = false;    });  }

整体架构

咱们将两种处理计划十分高雅地结合在了一起:

节日献礼:Flutter图片库重磅开源!

咱们抽象出了 PowerImageProvider ,关于 external(ffi)、texture,分别生产自己的 ImageInfo 即可。它将经过对 PowerImageLoade数组去重方法r 的flutter菜鸟教程调用,供给一致的加载与开释才能。

蓝色实线的 ImageExt 即为自定义的 Image Widget,为 texture 方法透出了 imageBuilder。

蓝色虚线 ImageCachswift语言eExt 即为 ImageCache 的扩展,仅在 flutter < 2.2.0 版别才需求,它将供给 ImageCache 开释机遇的回调。

这次,咱们也规划了超强的扩展才能。除缓存了支撑网络图、本地图、flutter 资源、native 资源外,咱们供给了自定义图片类型的通道,flutter 能够架构图怎么画传递任何自定义的参数组合给 native,只需 native 注册缓存视频怎样转入相册对应类型 loader,比方「相册」这种swifter场景,运用方能够自定义 imageType 为 album ,nativ数组指针e 运用自己的逻辑进行加载图片。有了这个自定义通道,甚至图片滤镜都能够运用 PowerImage 进行展现改写。

除了图片类型的扩展,渲染类型也可进行自定swift代码义。比方在上面 ffi 中说的,为了下降内存复制带来的峰值问题,运用方能够在 flu缓存视频合并apptter 侧进行解数组排序码,当然这需求 native 图片库供给解码前的数据。

数据:

FFI vs Texture:

节日献礼:Flutter图片库重磅开源!

机型:iPhone 11 Pro;图片:300 张网络图;行为:在listView中手动翻滚到底部再翻滚到顶部;native Cache:20 maxMemoryCount; flutter Cache:30MBflutter version 2.5.3; release 形式下

这里有两个现象:

FFI:   186MB动摇Texture: 194MB动摇

在 2.5.3 版别中,Texture 计划与 FFI,在内存水位上差异不flutter有必要学吗数组指针,内数组的定义存动摇上缓存清理面与 flutter 1.22 结论相反。

图中棋格图,为架构师和程序员的区别打开 che架构ckerboardRasterCacheImages 后所展现,能够看出,ffi计划会缓存整个cell,而texture计划,只要cell中的文字被缓存,RasterCache 会使得 ffi 在流畅度方面会有必定优势。

翻滚流畅性分析:

节日献礼:Flutter图片库重磅开源!

设备: Android OnePlus 8t,CPU和GPU进行了锁频。case: GridView每行4张图片,300张图片,从上往下,再从下往上,滑动起伏从500,1000,1500,2000,2500,5轮滑动。重复20次。方法: for i in {1..20}; do flutter drive --target=test_driver/app.dart --profile; done 跑数据,获取TimeLine数据并分析。

数组和链表的区别论:

  • • UI thread 耗时 texture 方法最好,PowerImage 略好于 IFImage,FFI方法动摇比较大。swifter
  • • Raster thread 耗时 PowerImage 好于数组 IFImage。Origin 原生方法好是因为对图片 resize了,其他方法加载的是原图。

更精简的代码:

节日献礼:Flutter图片库重磅开源!

dart 侧代码有较大起伏的削减,这归功数组去重方法于技能计划贴合swiftly fluswift语言tter 原生规划,咱们与原生图片共用较多代码。

FFI 计划补全了外接纹路flutteredflutter面试题缺乏,遵从原生 Image 的规划规范,不仅让咱们享受到 ImageCache 带来的一致办理,也带来了更精简的代码。

单测:

节日献礼:Flutter图片库重磅开源!

为了保证中心代码的稳定性,咱们有着较为完善的单测,行覆盖率接近95%。flutter开发的app有哪些

关于开源:

咱们等待经过社架构是什么意思区的力量让 PowerImage 愈加完swifter善与强壮,也期望 PowerImage 能为咱们在工程研制中带来收益。

Issues:数组

关于 issue,咱们期望咱们在运用 PowerImage 遇缓存视频变成本地视频到问题与诉求时,积极沟通,提出 issue 时尽可能供给详细的信息,以削减沟通本钱。架构图怎么制作在提出 issue 前,请保证已阅读 readme。

节日献礼:Flutter图片库重磅开源!

关于 bug 的 issue,咱们自定义swift是什么意思啊了模板(Bug report),能够方便地填一些必要的信息。其他类型则能够选择 Open a blank issue

咱们每周会花部swift代码分时间一致处理 issues,也等待咱们的讨论与 PR。

PR:

为了保持 PowerImage 中心功能的稳定性,咱们有着完善的单测,行覆盖率达到了 95%(power_缓存视频在手机哪里找image库)。数组词

在提交PR时,请保证所提交的代码被单测覆盖到,而且涉及到的单测代码请一起提交。

节日献礼:Flutter图片库重磅开源!

得益于 Github 的 Actions 才能,咱们在主分支 push 代码、对主分支进行 PR 操架构师作时,都会触发 flutter test使命,只要单测经过才可合入。

未来:

开源是 PowerImage 的开端,而不是完毕,PowerImage 可做的工作还有许多,风趣而丰厚。比方第一个 issue 中描述的flutter菜鸟教程 loa架构师和程序员的区别dingBuilder 怎么完成?比方 ffi 计划怎么支撑动图?再比方Kotlin和swift是什么组织缩写Swift

PowerImage 未来将继续演进,在当时 texture 计划与 ffi 计划共存的情况下,伴随着 flutter 自身的迭代,咱们将更倾向于向 ffi 发展,正如在上文的对比中, ffi 计划能够天然享受 raster cache 所带来的流畅度的优势。

PowerImage 也会继续追随 flutteflutter翻译r 的脚步,以一直贴合原生的规划理念,不断进步,咱们期望更多的同学加入进来,共同生长。

其他四个Flutter开源项目:闲鱼技能公众号-闲鱼开源

PowerImage相关链接:

GitHub:(✅star)

github.com/alibaba/pow…

Flutter pub:(✅like)

pub.dev/packages/po…