Adding ImageProvider.loadBuffer
Summary
#ImageProvider
now has a method calledloadBuffer
that functions similarly toload
, except that it decodes from anui.ImmutableBuffer
.ui.ImmutableBuffer
can now be created directly from an asset key.- The
AssetBundle
classes can now load anui.ImmutableBuffer
. - The
PaintingBinding
now has a method calledinstantiateImageCodecFromBuffer
, which functions similarly toinstantiateImageCodec
. ImageProvider.load
is now deprecated, it will be removed in a future release.PaintingBinding.instantiateImageCodec
is now deprecated, it will be removed in a future release.
Context
#ImageProvider.loadBuffer
is a new method that must be implemented in order to load images. This API allows asset-based image loading to be performed faster and with less memory impact on application.
Description of change
#When loading asset images, previously the image provider API required multiple copies of the compressed data. First, when opening the asset the data was copied into the external heap and exposed to Dart as a typed data array. Then that typed data array was eventually converted into an ui.ImmutableBuffer
, which internally copies the data into a second structure for decoding.
With the addition of ui.ImmutableBuffer.fromAsset
, compressed image bytes can be loaded directly into the structure used for decoding. Using this approach requires changes to the byte loading pipeline of ImageProvider
. This process is also faster, because it bypasses some additional scheduling overhead of the previous method channel based loader.
ImageProvider.loadBuffer
otherwise has the same contract as ImageProvider.load
, except it provides a new decoding callback that expects an ui.ImmutableBuffer
instead of a Uint8List
. For ImageProvider
classes that acquire bytes from places other than assets, the convenience method ui.ImmutableBuffer.fromUint8List
can be used for compatibility.
Migration guide
#Classes that subclass ImageProvider
must implement the loadBuffer
method for loading assets. Classes that delegate to or call the methods of an ImageProvider
directly must use loadBuffer
instead of load
.
Code before migration:
class MyImageProvider extends ImageProvider<MyImageProvider> {
@override
ImageStreamCompleter load(MyImageProvider key, DecoderCallback decode) {
return MultiFrameImageStreamCompleter(
codec: _loadData(key, decode),
);
}
Future<ui.Codec> _loadData(MyImageProvider key, DecoderCallback decode) async {
final Uint8List bytes = await bytesFromSomeApi();
return decode(bytes);
}
}
class MyDelegatingProvider extends ImageProvider<MyDelegatingProvider> {
MyDelegatingProvider(this.provider);
final ImageProvder provider;
@override
ImageStreamCompleter load(MyDelegatingProvider key, DecoderCallback decode) {
return provider.load(key, decode);
}
}
Code after migration:
class MyImageProvider extends ImageProvider<MyImageProvider> {
@override
ImageStreamCompleter loadBuffer(MyImageProvider key, DecoderBufferCallback decode) {
return MultiFrameImageStreamCompleter(
codec: _loadData(key, decode),
);
}
Future<ui.Codec> _loadData(MyImageProvider key, DecoderBufferCallback decode) async {
final Uint8List bytes = await bytesFromSomeApi();
final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromUint8List(bytes);
return decode(buffer);
}
}
class MyDelegatingProvider extends ImageProvider<MyDelegatingProvider> {
MyDelegatingProvider(this.provider);
final ImageProvder provider;
@override
ImageStreamCompleter loadBuffer(MyDelegatingProvider key, DecoderCallback decode) {
return provider.loadBuffer(key, decode);
}
}
In both cases you might choose to keep the previous implementation of ImageProvider.load
to give users of your code time to migrate as well.
Timeline
#Landed in version: 3.1.0-0.0.pre.976
In stable release: 3.3.0
References
#API documentation:
Relevant PR:
Unless stated otherwise, the documentation on this site reflects the latest stable version of Flutter. Page last updated on 2024-04-04. View source or report an issue.