resolve method

ImageStream resolve (ImageConfiguration configuration)

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.


ImageStream resolve(ImageConfiguration configuration) {
  assert(configuration != null);
  final ImageStream stream = ImageStream();
  T obtainedKey;
  bool didError = false;
  Future<void> handleError(dynamic exception, StackTrace stack) async {
    if (didError) {
    didError = true;
    await null; // wait an event turn in case a listener has been added to the image stream.
    final _ErrorImageCompleter imageCompleter = _ErrorImageCompleter();
      exception: exception,
      stack: stack,
      context: ErrorDescription('while resolving an image'),
      silent: true, // could be a network error or whatnot
      informationCollector: () sync* {
        yield DiagnosticsProperty<ImageProvider>('Image provider', this);
        yield DiagnosticsProperty<ImageConfiguration>('Image configuration', configuration);
        yield DiagnosticsProperty<T>('Image key', obtainedKey, defaultValue: null);

  // If an error is added to a synchronous completer before a listener has been
  // added, it can throw an error both into the zone and up the stack. Thus, it
  // looks like the error has been caught, but it is in fact also bubbling to the
  // zone. Since we cannot prevent all usage of Completer.sync here, or rather
  // that changing them would be too breaking, we instead hook into the same
  // zone mechanism to intercept the uncaught error and deliver it to the
  // image stream's error handler. Note that these errors may be duplicated,
  // hence the need for the `didError` flag.
  final Zone dangerZone = Zone.current.fork(
    specification: ZoneSpecification(
      handleUncaughtError: (Zone zone, ZoneDelegate delegate, Zone parent, Object error, StackTrace stackTrace) {
        handleError(error, stackTrace);
  dangerZone.runGuarded(() {
    Future<T> key;
    try {
      key = obtainKey(configuration);
    } catch (error, stackTrace) {
      handleError(error, stackTrace);
    key.then<void>((T key) {
      obtainedKey = key;
      final ImageStreamCompleter completer = PaintingBinding.instance
          .imageCache.putIfAbsent(key, () => load(key), onError: handleError);
      if (completer != null) {
  return stream;