Fix crash when a MultiFrameImageStreamCompleter is disposed during frame decoding (#69219)

diff --git a/packages/flutter/lib/src/painting/image_stream.dart b/packages/flutter/lib/src/painting/image_stream.dart
index abffeee..1b6a8a5 100644
--- a/packages/flutter/lib/src/painting/image_stream.dart
+++ b/packages/flutter/lib/src/painting/image_stream.dart
@@ -920,6 +920,12 @@
       return;
     }
     if (_codec!.frameCount == 1) {
+      // ImageStreamCompleter listeners removed while waiting for next frame to
+      // be decoded.
+      // There's no reason to emit the frame without active listeners.
+      if (!hasListeners) {
+        return;
+      }
       // This is not an animated image, just return it and don't schedule more
       // frames.
       _emitFrame(ImageInfo(
diff --git a/packages/flutter/test/painting/image_stream_test.dart b/packages/flutter/test/painting/image_stream_test.dart
index 491b115..6b98462 100644
--- a/packages/flutter/test/painting/image_stream_test.dart
+++ b/packages/flutter/test/painting/image_stream_test.dart
@@ -130,6 +130,31 @@
     expect(mockCodec.numFramesAsked, 1);
   });
 
+  testWidgets('Decoding does not crash when disposed', (WidgetTester tester) async {
+    final Completer<Codec> completer = Completer<Codec>();
+    final MockCodec mockCodec = MockCodec();
+    mockCodec.frameCount = 1;
+    final ImageStreamCompleter imageStream = MultiFrameImageStreamCompleter(
+      codec: completer.future,
+      scale: 1.0,
+    );
+
+    completer.complete(mockCodec);
+    await tester.idle();
+    expect(mockCodec.numFramesAsked, 0);
+
+    final ImageListener listener = (ImageInfo image, bool synchronousCall) { };
+    final ImageStreamListener streamListener = ImageStreamListener(listener);
+    imageStream.addListener(streamListener);
+    await tester.idle();
+    expect(mockCodec.numFramesAsked, 1);
+
+    final FrameInfo frame = FakeFrameInfo(const Duration(milliseconds: 200), image20x10);
+    mockCodec.completeNextFrame(frame);
+    imageStream.removeListener(streamListener);
+    await tester.idle();
+  });
+
   testWidgets('Chunk events of base ImageStreamCompleter are delivered', (WidgetTester tester) async {
     final List<ImageChunkEvent> chunkEvents = <ImageChunkEvent>[];
     final StreamController<ImageChunkEvent> streamController = StreamController<ImageChunkEvent>();