Add outer try block for obtainKey errors. Add docs. (#27953) * Add outer try block for obtainKey errors. Add docs. * change to // from ///, and do specific error handling * Add return statement after error * Add test
diff --git a/packages/flutter/lib/src/painting/image_provider.dart b/packages/flutter/lib/src/painting/image_provider.dart index 161517d..1a2845c 100644 --- a/packages/flutter/lib/src/painting/image_provider.dart +++ b/packages/flutter/lib/src/painting/image_provider.dart
@@ -280,13 +280,28 @@ } ); } - obtainKey(configuration).then<void>((T key) { + + // `obtainKey` can throw both sync and async errors. + // `catchError` handles cases where async errors are thrown and the try block is for sync errors. + // + // `onError` callback on [ImageCache] handles the cases where `obtainKey` is a sync future and `load` throws. + Future<T> key; + try { + key = obtainKey(configuration); + } catch (error, stackTrace) { + handleError(error, stackTrace); + return stream; + } + + key.then<void>((T key) { obtainedKey = key; - final ImageStreamCompleter completer = PaintingBinding.instance.imageCache.putIfAbsent(key, () => load(key), onError: handleError); + final ImageStreamCompleter completer = PaintingBinding.instance + .imageCache.putIfAbsent(key, () => load(key), onError: handleError); if (completer != null) { stream.setCompleter(completer); } }).catchError(handleError); + return stream; }
diff --git a/packages/flutter/test/painting/image_provider_test.dart b/packages/flutter/test/painting/image_provider_test.dart index 51e698e..b49e5e9 100644 --- a/packages/flutter/test/painting/image_provider_test.dart +++ b/packages/flutter/test/painting/image_provider_test.dart
@@ -71,4 +71,19 @@ expect(await caughtError.future, true); }); }); + + test('ImageProvide.obtainKey errors will be caught', () async { + final ImageProvider imageProvider = ObtainKeyErrorImageProvider(); + final Completer<bool> caughtError = Completer<bool>(); + FlutterError.onError = (FlutterErrorDetails details) { + caughtError.complete(false); + }; + final ImageStream stream = imageProvider.resolve(ImageConfiguration.empty); + stream.addListener((ImageInfo info, bool syncCall) { + caughtError.complete(false); + }, onError: (dynamic error, StackTrace stackTrace) { + caughtError.complete(true); + }); + expect(await caughtError.future, true); + }); }
diff --git a/packages/flutter/test/painting/mocks_for_image_cache.dart b/packages/flutter/test/painting/mocks_for_image_cache.dart index 0425500..e0353d3 100644 --- a/packages/flutter/test/painting/mocks_for_image_cache.dart +++ b/packages/flutter/test/painting/mocks_for_image_cache.dart
@@ -94,4 +94,16 @@ } } +class ObtainKeyErrorImageProvider extends ImageProvider<ObtainKeyErrorImageProvider> { + @override + ImageStreamCompleter load(ObtainKeyErrorImageProvider key) { + throw Error(); + } + + @override + Future<ObtainKeyErrorImageProvider> obtainKey(ImageConfiguration configuration) { + throw Error(); + } +} + class TestImageStreamCompleter extends ImageStreamCompleter {}