SoFunction
Updated on 2025-04-06

Analysis of ImageProvider source code example of Flutter loading image process

Loading network pictures

()is a method provided by Flutter to load images from the network, which can load images from a specified URL and display them in the application after loading is complete. In this section, we will discuss the loading process of the image based on the source code.

ImageProvider

ImageProviderIt is an abstract class in Flutter. It defines a common interface for loading pictures, which can be used to load local pictures, network pictures and other types of pictures.

ImageProviderThe class contains two core methods:obtainKeyandloadBuffer

resolve

/// Resolves this image provider using the given `configuration`, returning
/// an [ImageStream].
///
/// This is the public entry-point of the [ImageProvider] class hierarchy.
///
/// Subclasses should implement [obtainKey] and [load], which are used by this
/// method. If they need to change the implementation of [ImageStream] used,
/// they should override [createStream]. If they need to manage the actual
/// resolution of the image, they should override [resolveStreamForKey].
///
/// See the Lifecycle documentation on [ImageProvider] for more information.
@nonVirtual
ImageStream resolve(ImageConfiguration configuration) {
  assert(configuration != null);
  final ImageStream stream = createStream(configuration);
  // Load the key (potentially asynchronously), set up an error handling zone,
  // and call resolveStreamForKey.
  _createErrorHandlerAndKey(
    configuration,
    (T key, ImageErrorListener errorHandler) {
      resolveStreamForKey(configuration, stream, key, errorHandler);
    },
    (T? key, Object exception, StackTrace? stack) async {
      await null; // wait an event turn in case a listener has been added to the image stream.
      InformationCollector? collector;
      assert(() {
        collector = () => <DiagnosticsNode>[          DiagnosticsProperty<ImageProvider>('Image provider', this),          DiagnosticsProperty<ImageConfiguration>('Image configuration', configuration),          DiagnosticsProperty<T>('Image key', key, defaultValue: null),        ];
        return true;
      }());
      if ( == null) {
        (_ErrorImageCompleter());
      }
      !.reportError(
        exception: exception,
        stack: stack,
        context: ErrorDescription('while resolving an image'),
        silent: true, // could be a network error or whatnot
        informationCollector: collector,
      );
    },
  );
  return stream;
}

According to the documentation, we can learn the following:

1. Use the given `configuration` to parse the image provider and return a [ImageStream].

2. This is the public entry point of the [ImageProvider] class hierarchy.

3. Subclasses should implement the [obtainKey] and [load] methods, and these two methods will be used by this method.

4. If the subclass needs to change the implementation of [ImageStream] used, the [createStream] method should be overridden.

5. If the subclass needs to manage the actual image resolution, the [resolveStreamForKey] method should be overridden.

readresolveImplementation of the method. We can know:

1. It uses the givenconfigurationCreate a parameterImageStreamObject(createStream). Then call_createErrorHandlerAndKeyMethod, This method will asynchronously obtain the unique identifier of the image and set an error handling area to prevent errors from occurring during the image loading process.

2. If an exception occurs during the process of obtaining a unique identifier, the error message will be encapsulated into one_ErrorImageCompleterobject, and set it toImageStreamofcompleterAttribute, indicating that the image has failed to load.

3. If the unique identifier is successfully obtained, it will be calledresolveStreamForKeyMethod to parse pictures and store picture data toImageStreamIn the object, for subsequent use.

4. This method isImageProviderThe common entry point of the class hierarchy, as it is the parsing method for all image providers. Subclasses only need to be implementedobtainKeyandloadMethod to get the unique identifier of the image and load the image data without rewritingresolvemethod.

5. If the subclass needs to be changedImageStreamThe implementation method can be rewrittencreateStreammethod. If the subclass needs to manage the actual image resolution, it can be rewritedresolveStreamForKeymethod. For example,AssetImageIn the classcreateStreamMethod returns aAssetBundleImageStreamCompleterObject, which is used to load image data from application resources. andNetworkImageIn the classresolveStreamForKeyMethods Use HTTP client to load image data from the network.

6. There is also some debugging information in this code, such as adding image providers, image configurations, and image unique identifiers to the debugging information to debug when an error occurs.

obtainKey

/// Converts an ImageProvider's settings plus an ImageConfiguration to a key
/// that describes the precise image to load.
///
/// The type of the key is determined by the subclass. It is a value that
/// unambiguously identifies the image (_including its scale_) that the [load]
/// method will fetch. Different [ImageProvider]s given the same constructor
/// arguments and [ImageConfiguration] objects should return keys that are
/// '==' to each other (possibly by using a class for the key that itself
/// implements [==]).
Future&lt;T&gt; obtainKey(ImageConfiguration configuration);

This comment is aboutobtainKeyDescription of the method. This method isImageProviderOne of the methods that should be implemented by subclassing theImageProviderSettings andImageConfigurationConvert to a uniquely identifiable imagekey

DifferentImageProviderAccording to the same constructor parameters andImageConfigurationThe object should return equalkey, to facilitate subsequent loading and cache images.keyThe type of ,is determined by the subclass, should be a value that uniquely identifies the image to be loaded (including its scaling).

In realizingobtainKeyWhen a method is used, subclasses can consider using custom classes to represent them.key, and implement==Method to ensure uniqueness.

resolveStreamForKey

@protected
void resolveStreamForKey(ImageConfiguration configuration, ImageStream stream, T key, ImageErrorListener handleError) {
  // This is an unusual edge case where someone has told us that they found
  // the image we want before getting to this method. We should avoid calling
  // load again, but still update the image cache with LRU information.
  if ( != null) {
    final ImageStreamCompleter? completer = (
      key,
      () =&gt; !,
      onError: handleError,
    );
    assert(identical(completer, ));
    return;
  }
  final ImageStreamCompleter? completer = (
    key,
    /// load    () =&gt; loadBuffer(key, ),
    onError: handleError,
  );
  if (completer != null) {
    /// The key is to parse and set the ImageStreamCompleter object    (completer);
  }
}

Official documentation explanation:

  • This method isImageProviderOne of the methods that should be implemented by subclasses ofkeyTo parse the picture.
  • resolveStreamForKeyThe method is fromresolveThe parameters of the method call includeImageConfigurationImageStreamkeyanderrorHandler. Subclasses can be implementedresolveStreamForKeyMethods to manage the actual parsing process of images, and can also be callederrorHandlerTo handle errors that may occur during parsing.
  • accomplishresolveStreamForKeyWhen using a method, subclasses can consider usingkeyandImageCacheInteraction, such as callingMethod andstreamNotify the listener. The default implementation has been usedkeyandImageCacheInteraction, subclasses can choose to callMethod or not called.

From the above source code, we can know the following points:

  • 1. IfstreamThe object already existscompleter(that is, there is already a way to load the picture), thencompleterAdd toImageCache, implement the cache function and return directly.
  • 2. IfstreamThere is no object yetcompleter, then callloadBufferMethod loads the image and returns itImageStreamCompleterObject added toImageCacheand set tostreamThe object'scompletermiddle.
  • 3. IfloadBufferIf an exception occurs in the method, the exception will be handed over toonErrorCallback processing so that detailed error information can be provided during exception handling.
  • 4. The key is to parse and set upImageStreamCompleterObject
  • 5、The method internallyImageStreamListenerObject added toImageStreamCompleterThe object's_listenersThe array is in.
   (
     key,
     () =&gt; loadBuffer(key, ),
     onError: handleError,
   )

loadBuffer

/// Converts a key into an [ImageStreamCompleter], and begins fetching the
/// image.
///
/// For backwards-compatibility the default implementation of this method calls
/// through to []. However, implementors of this interface should
/// only override this method and not [], which is deprecated.
///
/// The [decode] callback provides the logic to obtain the codec for the
/// image.
///
/// See also:
///
///  * [ResizeImage], for modifying the key to account for cache dimensions.
@protected
ImageStreamCompleter loadBuffer(T key, DecoderBufferCallback decode) {
  return load(key, );
}

From the source code, we know that[], which is deprecatedAbandoned. Subclasses only need to be rewriteloadBufferJust the method.

  • This method is a protected method of ImageProvider, which is used to load the specified image from the cache.
  • It accepts two parameters: one is the key that uniquely identifies the image, and the other is a callback function decode used to decode the image data.
  • This method calls the load method and returns an ImageStreamCompleter object, which represents a data stream during loading.
  • In the load method, the incoming decode callback function is used to obtain image data from the cache or network and decode it, and then the decoded image data is passed to the ImageStreamCompleter object so that it can generate an ImageInfo object with the correct image data, which can be passed into the Image widget for displaying the image.

load(deprecated)

/// Converts a key into an [ImageStreamCompleter], and begins fetching the
/// image.
///
/// This method is deprecated. Implement [loadBuffer] for faster image
/// loading. Only one of [load] and [loadBuffer] must be implemented, and
/// [loadBuffer] is preferred.
///
/// The [decode] callback provides the logic to obtain the codec for the
/// image.
///
/// See also:
///
///  * [ResizeImage], for modifying the key to account for cache dimensions.
@protected
@Deprecated(
  'Implement loadBuffer for faster image loading. '
  'This feature was deprecated after v2.13.0-1..',
)
ImageStreamCompleter load(T key, DecoderCallback decode) {
  throw UnsupportedError('Implement loadBuffer for faster image loading');
}

From the comments, we can see:

This method has been abandoned and is no longer recommended for use. If you need faster image loading, implement the [loadBuffer] method. Only one of them is required in the [load] and [loadBuffer] methods, and [loadBuffer] is more recommended.

[decode] Callback provides the logic for getting the image codec.

evict

/// Evicts an entry from the image cache.
///
/// Returns a [Future] which indicates whether the value was successfully
/// removed.
///
/// The [ImageProvider] used does not need to be the same instance that was
/// passed to an [Image] widget, but it does need to create a key which is
/// equal to one.
///
/// The [cache] is optional and defaults to the global image cache.
///
/// The [configuration] is optional and defaults to
/// [].
///
/// {@tool snippet}
///
/// The following sample code shows how an image loaded using the [Image]
/// widget can be evicted using a [NetworkImage] with a matching URL.
///
/// ```dart
/// class MyWidget extends StatelessWidget {
///   const MyWidget({
///     ,
///      = ' ... ',
///   });
///
///   final String url;
///
///   @override
///   Widget build(BuildContext context) {
///     return (url);
///   }
///
///   void evictImage() {
///     final NetworkImage provider = NetworkImage(url);
///     ().then&lt;void&gt;((bool success) {
///       if (success) {
///         debugPrint('removed image!');
///       }
///     });
///   }
/// }
/// ```
/// {@end-tool}
Future&lt;bool&gt; evict({ ImageCache? cache, ImageConfiguration configuration =  }) async {
  cache ??= imageCache;
  final T key = await obtainKey(configuration);
  return (key);
}

This is a namedevictThe asynchronous method of , which is used to delete the image in a given configuration from the image cache. It has two optional parameters:cacheandconfiguration. ifcacheThe parameter is null, and the global one is used by default.imageCacheconfigurationThe parameter is an image configuration that gets the key value of the image to be deleted from the cache. This method returns aFuture<bool>Object, indicating whether the deletion is successful. If no image to be deleted is found in the cache, returnfalse

When the list slides quickly, you can use this method to do something when the memory skyrockets.

Summarize

ImageProvideris an abstract class in Flutter that provides image data. It defines how to obtain image data from different data sources (such as file system, network, memory) and convert it intoImageStreamCompleterObject, forImageComponent use.

In Flutter, useImageComponents to load and display images need to provide aImageProviderObject as itsimageThe value of the attribute.ImageProviderThe class contains two key methods:obtainKeyandload

obtainKeyMethod is used to obtain a uniquely identified image dataImageProviderObject, This object can be used to cache image data so that it can be quickly retrieved when the image needs to be reloaded. For example,AssetImageThe class uses the path of the image resource as itsImageProviderThe identifier of the object so that it can be quickly retrieved from the memory or disk cache when it needs to be reloaded.

loadMethod is used to obtain aImageStreamCompleterObject, which contains image data used to draw an image. Before Flutter 2.5,loadA method is an abstract method that must be implemented by a subclass. But starting with Flutter 2.5,loadThe method has been abandoned and replaced byresolvemethod.resolveMethod accepts aImageConfigurationparameter and return aFuture<ImageStreamCompleter>Object. It's withloadThe functions of the method are similar, both are used to obtain image data and convert it intoImageStreamCompleterObject, forImageComponent use.

useImageProviderThe process of class loading and displaying images is as follows:

  • Create aImageProviderObject, which provides the source and identifier of image data.
  • useImageProviderObject asImageComponentimageThe value of the attribute.
  • ImageThe component will callobtainKeyMethod to obtain a uniquely identified image dataImageProviderObject.
  • ImageThe component will callresolveMethod to get oneFuture<ImageStreamCompleter>Object.
  • When the image data is loaded,ImageStreamCompleterThe object will notify it toImageComponents,ImageThe component renders it to the screen.

Overall,ImageProviderClasses are a very important class in Flutter, which provides a convenient way to load and display images. AlthoughloadThe method has been abandoned, butresolveMethods provide better alternatives that can be used to acquire image data and convert it intoImageStreamCompleterObject.

Reference link

Analysis of network image loading process of Flutter system_Android

Flutter Introduction Series (IV) ---Flutter Picture Cache

Flutter | Image Source code analysis and optimization method

Confused answer

When the picture is loaded for the first time,streamObjects usually have nocompleter. On the first callresolveStreamForKeyWhen thestreamThe object'scompleterand correspondingImageCacheofImageStreamCompleterMake binding, andcompleterWill be set toImageStreamCompleter

The above is the detailed analysis of the ImageProvider source code example of Flutter loading image process. For more information about Flutter loading image ImageProvider, please follow my other related articles!