diff --git a/packages/flutter/lib/src/services/image_provider.dart b/packages/flutter/lib/src/services/image_provider.dart index 1d470127b6..2a1f229bc6 100644 --- a/packages/flutter/lib/src/services/image_provider.dart +++ b/packages/flutter/lib/src/services/image_provider.dart @@ -528,6 +528,12 @@ class FileImage extends ImageProvider { /// Decodes the given [Uint8List] buffer as an image, associating it with the /// given scale. +/// +/// The provided [bytes] buffer should not be changed after it is provided +/// to a [MemoryImage]. To provide an [ImageStream] that represents an image +/// that changes over time, consider creating a new subclass of [ImageProvider] +/// whose [load] method returns a subclass of [ImageStreamCompleter] that can +/// handle providing multiple images. class MemoryImage extends ImageProvider { /// Creates an object that decodes a [Uint8List] buffer as an image. /// @@ -580,6 +586,7 @@ class MemoryImage extends ImageProvider { @override String toString() => '$runtimeType(${describeIdentity(bytes)}, scale: $scale)'; } + /// Fetches an image from an [AssetBundle], associating it with the given scale. /// /// This implementation requires an explicit final [name] and [scale] on diff --git a/packages/flutter/lib/src/services/image_stream.dart b/packages/flutter/lib/src/services/image_stream.dart index 55a3cdfee3..54a9f937f6 100644 --- a/packages/flutter/lib/src/services/image_stream.dart +++ b/packages/flutter/lib/src/services/image_stream.dart @@ -88,6 +88,10 @@ class ImageStream { /// /// This is usually done automatically by the [ImageProvider] that created the /// [ImageStream]. + /// + /// This method can only be called once per stream. To have an [ImageStream] + /// represent multiple images over time, assign it a completer that + /// completes several images in succession. void setCompleter(ImageStreamCompleter value) { assert(_completer == null); _completer = value; @@ -98,9 +102,17 @@ class ImageStream { } } - /// Adds a listener callback that is called whenever a concrete [ImageInfo] + /// Adds a listener callback that is called whenever a new concrete [ImageInfo] /// object is available. If a concrete image is already available, this object /// will call the listener synchronously. + /// + /// If the assigned [completer] completes multiple images over its lifetime, + /// this listener will fire multiple times. + /// + /// The listener will be passed a flag indicating whether a synchronous call + /// occurred. If the listener is added within a render object paint function, + /// then use this flag to avoid calling [RenderObject.markNeedsPaint] during + /// a paint. void addListener(ImageListener listener) { if (_completer != null) return _completer.addListener(listener); @@ -161,13 +173,17 @@ class ImageStreamCompleter { final List _listeners = []; ImageInfo _current; - /// Adds a listener callback that is called whenever a concrete [ImageInfo] + /// Adds a listener callback that is called whenever a new concrete [ImageInfo] /// object is available. If a concrete image is already available, this object /// will call the listener synchronously. /// + /// If the assigned [completer] completes multiple images over its lifetime, + /// this listener will fire multiple times. + /// /// The listener will be passed a flag indicating whether a synchronous call /// occurred. If the listener is added within a render object paint function, - /// then use this flag to avoid calling markNeedsPaint during a paint. + /// then use this flag to avoid calling [RenderObject.markNeedsPaint] during + /// a paint. void addListener(ImageListener listener) { _listeners.add(listener); if (_current != null) { @@ -254,7 +270,8 @@ class OneFrameImageStreamCompleter extends ImageStreamCompleter { stack: stack, library: 'services', context: 'resolving a single-frame image stream', - informationCollector: informationCollector + informationCollector: informationCollector, + silent: true, )); }); }