mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
correctly dispose listeners by image widget (#57201)
This commit is contained in:
parent
8abf0a6d8c
commit
79ad2d2e20
@ -1079,8 +1079,8 @@ class _ImageState extends State<Image> with WidgetsBindingObserver {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (_isListeningToStream &&
|
||||
(widget.loadingBuilder == null) != (oldWidget.loadingBuilder == null)) {
|
||||
_imageStream.removeListener(_getListener(oldWidget.loadingBuilder));
|
||||
_imageStream.addListener(_getListener());
|
||||
_imageStream.removeListener(_getListener());
|
||||
_imageStream.addListener(_getListener(recreateListener: true));
|
||||
}
|
||||
if (widget.image != oldWidget.image)
|
||||
_resolveImage();
|
||||
@ -1119,22 +1119,25 @@ class _ImageState extends State<Image> with WidgetsBindingObserver {
|
||||
_updateSourceStream(newStream);
|
||||
}
|
||||
|
||||
ImageStreamListener _getListener([ImageLoadingBuilder loadingBuilder]) {
|
||||
loadingBuilder ??= widget.loadingBuilder;
|
||||
_lastException = null;
|
||||
_lastStack = null;
|
||||
return ImageStreamListener(
|
||||
_handleImageFrame,
|
||||
onChunk: loadingBuilder == null ? null : _handleImageChunk,
|
||||
onError: widget.errorBuilder != null
|
||||
? (dynamic error, StackTrace stackTrace) {
|
||||
setState(() {
|
||||
_lastException = error;
|
||||
_lastStack = stackTrace;
|
||||
});
|
||||
}
|
||||
: null,
|
||||
);
|
||||
ImageStreamListener _imageStreamListener;
|
||||
ImageStreamListener _getListener({bool recreateListener = false}) {
|
||||
if(_imageStreamListener == null || recreateListener) {
|
||||
_lastException = null;
|
||||
_lastStack = null;
|
||||
_imageStreamListener = ImageStreamListener(
|
||||
_handleImageFrame,
|
||||
onChunk: widget.loadingBuilder == null ? null : _handleImageChunk,
|
||||
onError: widget.errorBuilder != null
|
||||
? (dynamic error, StackTrace stackTrace) {
|
||||
setState(() {
|
||||
_lastException = error;
|
||||
_lastStack = stackTrace;
|
||||
});
|
||||
}
|
||||
: null,
|
||||
);
|
||||
}
|
||||
return _imageStreamListener;
|
||||
}
|
||||
|
||||
void _handleImageFrame(ImageInfo imageInfo, bool synchronousCall) {
|
||||
|
@ -1331,6 +1331,73 @@ void main() {
|
||||
expect(tester.binding.hasScheduledFrame, isFalse);
|
||||
}, skip: isBrowser);
|
||||
|
||||
testWidgets('Verify Image resets its ImageListeners', (WidgetTester tester) async {
|
||||
final GlobalKey key = GlobalKey();
|
||||
final TestImageStreamCompleter imageStreamCompleter = TestImageStreamCompleter();
|
||||
final TestImageProvider imageProvider1 = TestImageProvider(streamCompleter: imageStreamCompleter);
|
||||
await tester.pumpWidget(
|
||||
Container(
|
||||
key: key,
|
||||
child: Image(
|
||||
image: imageProvider1,
|
||||
),
|
||||
),
|
||||
);
|
||||
// listener from resolveStreamForKey is always added.
|
||||
expect(imageStreamCompleter.listeners.length, 2);
|
||||
|
||||
|
||||
final TestImageProvider imageProvider2 = TestImageProvider();
|
||||
await tester.pumpWidget(
|
||||
Container(
|
||||
key: key,
|
||||
child: Image(
|
||||
image: imageProvider2,
|
||||
excludeFromSemantics: true,
|
||||
),
|
||||
),
|
||||
null,
|
||||
EnginePhase.layout,
|
||||
);
|
||||
|
||||
// only listener from resolveStreamForKey is left.
|
||||
expect(imageStreamCompleter.listeners.length, 1);
|
||||
});
|
||||
|
||||
testWidgets('Verify Image resets its ErrorListeners', (WidgetTester tester) async {
|
||||
final GlobalKey key = GlobalKey();
|
||||
final TestImageStreamCompleter imageStreamCompleter = TestImageStreamCompleter();
|
||||
final TestImageProvider imageProvider1 = TestImageProvider(streamCompleter: imageStreamCompleter);
|
||||
await tester.pumpWidget(
|
||||
Container(
|
||||
key: key,
|
||||
child: Image(
|
||||
image: imageProvider1,
|
||||
errorBuilder: (_,__,___) => Container(),
|
||||
),
|
||||
),
|
||||
);
|
||||
// listener from resolveStreamForKey is always added.
|
||||
expect(imageStreamCompleter.listeners.length, 2);
|
||||
|
||||
|
||||
final TestImageProvider imageProvider2 = TestImageProvider();
|
||||
await tester.pumpWidget(
|
||||
Container(
|
||||
key: key,
|
||||
child: Image(
|
||||
image: imageProvider2,
|
||||
excludeFromSemantics: true,
|
||||
),
|
||||
),
|
||||
null,
|
||||
EnginePhase.layout,
|
||||
);
|
||||
|
||||
// only listener from resolveStreamForKey is left.
|
||||
expect(imageStreamCompleter.listeners.length, 1);
|
||||
});
|
||||
|
||||
testWidgets('Image defers loading while fast scrolling', (WidgetTester tester) async {
|
||||
const int gridCells = 1000;
|
||||
final List<TestImageProvider> imageProviders = <TestImageProvider>[];
|
||||
|
Loading…
Reference in New Issue
Block a user