perf(mornye): release outgoing artwork decoders when replaced

Retain the outgoing decoder only while its frame remains displayed, then release its provider subscription as soon as replacement artwork is ready. Verify decoder disposal while preserving cover transitions.
This commit is contained in:
zarzet
2026-09-20 17:20:52 +07:00
parent a7717ddfbf
commit 6038ce5777
2 changed files with 8 additions and 5 deletions
+6 -5
View File
@@ -53,11 +53,6 @@ class _MornyePlayerArtworkState extends ConsumerState<MornyePlayerArtwork> {
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<MornyePlayerArtwork> {
_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: [
+2
View File
@@ -181,6 +181,8 @@ void main() {
ready(2);
await tester.pump();
await tester.pump();
await tester.runAsync(() => Future<void>.delayed(Duration.zero));
expect(platform.disposals, 1, reason: 'Release the outgoing decoder');
expect(
tester
.widget<MotionHeaderBanner>(find.byType(MotionHeaderBanner))