diff --git a/lib/widgets/mornye_player_artwork.dart b/lib/widgets/mornye_player_artwork.dart index 4bfa3129..5680c74e 100644 --- a/lib/widgets/mornye_player_artwork.dart +++ b/lib/widgets/mornye_player_artwork.dart @@ -53,11 +53,6 @@ class _MornyePlayerArtworkState extends ConsumerState { return fallback; } final videoUrl = widget.videoUrl; - // Keep one outgoing decoder alive until the next cover is ready. Rapid - // skips must not replace a visible frame with a loading placeholder. - if (_displayedSource != null && _displayedSource != videoUrl) { - ref.watch(playerArtworkVideoProvider(_displayedSource!)); - } final prepared = videoUrl == null ? null : ref.watch(playerArtworkVideoProvider(videoUrl)); @@ -74,6 +69,12 @@ class _MornyePlayerArtworkState extends ConsumerState { _displayedSource = null; _displayedController = null; } + // Retain the outgoing decoder only while it is still displayed. Watching + // it before accepting the new frame keeps its heap alive until a later + // unrelated rebuild, even after the old banner has been removed. + if (_displayedSource != null && _displayedSource != videoUrl) { + ref.watch(playerArtworkVideoProvider(_displayedSource!)); + } return Stack( fit: StackFit.expand, children: [ diff --git a/test/motion_header_banner_test.dart b/test/motion_header_banner_test.dart index f0949542..65979cb7 100644 --- a/test/motion_header_banner_test.dart +++ b/test/motion_header_banner_test.dart @@ -181,6 +181,8 @@ void main() { ready(2); await tester.pump(); await tester.pump(); + await tester.runAsync(() => Future.delayed(Duration.zero)); + expect(platform.disposals, 1, reason: 'Release the outgoing decoder'); expect( tester .widget(find.byType(MotionHeaderBanner))