Saltar al contenido principal

Agregando ImageProvider.loadBuffer

Los ImageProvider ahora deben ser implementados utilizando la nueva API loadBuffer en lugar de la API load existente.

Resumen

#
  • ImageProvider ahora tiene un método llamado loadBuffer que funciona de manera similar a load, excepto que decodifica desde un ui.ImmutableBuffer.
  • ui.ImmutableBuffer ahora se puede crear directamente desde una clave de recurso (asset key).
  • Las clases AssetBundle ahora pueden cargar un ui.ImmutableBuffer.
  • El PaintingBinding ahora tiene un método llamado instantiateImageCodecFromBuffer, el cual funciona de manera similar a instantiateImageCodec.
  • ImageProvider.load ahora está obsoleto, se eliminará en un lanzamiento futuro.
  • PaintingBinding.instantiateImageCodec ahora está obsoleto, se eliminará en un lanzamiento futuro.

Contexto

#

ImageProvider.loadBuffer es un nuevo método que debe implementarse para cargar imágenes. Esta API permite que la carga de imágenes basadas en recursos (assets) se realice más rápido y con un menor impacto de memoria en la aplicación.

Descripción del cambio

#

Al cargar imágenes de recursos (assets), anteriormente la API del proveedor de imágenes requería múltiples copias de los datos comprimidos. Primero, al abrir el recurso, los datos se copiaban en el montón (heap) externo y se exponían a Dart como una matriz de datos tipados (typed data array). Luego esa matriz de datos tipados finalmente se convertía en un ui.ImmutableBuffer, el cual copia internamente los datos a una segunda estructura para su decodificación.

Con la adición de ui.ImmutableBuffer.fromAsset, los bytes de la imagen comprimida se pueden cargar directamente en la estructura utilizada para la decodificación. Usar este enfoque requiere cambios en la canalización (pipeline) de carga de bytes de ImageProvider. Este proceso es también más rápido porque omite cierta sobrecarga de programación adicional del cargador anterior basado en canales de métodos (method channels).

Por lo demás, ImageProvider.loadBuffer tiene el mismo contrato que ImageProvider.load, excepto que proporciona un nuevo callback de decodificación que espera un ui.ImmutableBuffer en lugar de un Uint8List. Para las clases ImageProvider que adquieren bytes de lugares distintos a los recursos (assets), se puede utilizar el método de conveniencia ui.ImmutableBuffer.fromUint8List por motivos de compatibilidad.

Guía de migración

#

Las clases que heredan de ImageProvider deben implementar el método loadBuffer para cargar recursos (assets). Las clases que delegan o llaman a los métodos de un ImageProvider directamente deben usar loadBuffer en lugar de load.

Código antes de la migración:

dart
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 ImageProvider provider;

  @override
  ImageStreamCompleter load(MyDelegatingProvider key, DecoderCallback decode) {
    return provider.load(key, decode);
  }
}

Código después de la migración:

dart
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 ImageProvider provider;

  @override
  ImageStreamCompleter loadBuffer(MyDelegatingProvider key, DecoderCallback decode) {
    return provider.loadBuffer(key, decode);
  }
}

En ambos casos, podrías optar por mantener la implementación anterior de ImageProvider.load para dar tiempo a los usuarios de tu código a migrar también.

Timeline

#

Introducido en la versión: 3.1.0-0.0.pre.976
En el lanzamiento estable: 3.3.0

Referencias

#

Documentación de la API:

PR relevante: