NSData *data = CFBridgingRelease(rawDataRef);
self.data = data;
_length = data.length;
dart 侧拿到后
@override
FutureOr createImageInfo(Map map) {
Completer completer = Completer();
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 pointer = Pointer.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 拿到 native 内存,从而生成 ui.Image。这里有个问题,虽然通过 ffi 能直接获取 native 内存,但是由于 decodeImageFromPixels
会有内存拷贝,在拷贝解码后的图片数据时,内存峰值会更加严重。
这里有两个优化方向:
-
解码前的图片数据给 flutter,由 flutter 提供的解码器解码,从而削减内存拷贝峰值。
-
与 flutter 官方讨论,尝试从内部减少这次内存拷贝。
FFI 这种方式适合轻度使用、特殊场景使用,支持这种方式可以解决无法获取 ui.Image 的问题,也可以在模拟器上展示图片(flutter <= 1.23.0-18.1.pre),并且图片缓存将完全交给 ImageCache 管理。
▐ Texture
Texture 方案与原生结合有一些难度,这里涉及到没有 ui.Image
只有 textureId。这里有几个问题需要解决:
问题一:Image Widget 需要 ui.Image
去 build RawImage
从而绘制,这在本文前面的Flutter 原生方案介绍中也提到了。
问题二:ImageCache 依赖 ImageInfo 中 ui.Image
的宽高进行 cache 大小计算以及缓存前的校验。
问题三:native 侧 texture 生命周期管理
都有解决方案:
问题一:通过自定义 Image 解决,透出 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,