fix(player): 修复切换频道时复用已释放的视频控制器

This commit is contained in:
Zhou Weidong committed 2026-10-21 20:00:15 +08:00
1 parent 45a53180d9
commit f3ec12e3c3
6 files changed
+229 -6

No files matched your search

+25 -3
View File
@@ -49,6 +49,7 @@ class PlaybackSession extends ChangeNotifier {
this.prepare,
this.activate,
PlaybackCoordinator? coordinator,
this.waitForFrame,
}) : _coordinator = coordinator ?? PlaybackCoordinator();
final List<Episode> episodes;
@@ -60,6 +61,7 @@ class PlaybackSession extends ChangeNotifier {
/// Runs only when a slot becomes current (e.g. progress listeners).
final PlayerPreparation? activate;
final Future<void> Function()? waitForFrame;
final PlaybackCoordinator _coordinator;
final Set<_PlayerSlot> _live = {};
_PlayerSlot? _active;
@@ -80,8 +82,16 @@ class PlaybackSession extends ChangeNotifier {
int get currentIndex => _currentIndex;
Episode get currentEpisode => episodes[_currentIndex];
PlayerPort? get active =>
_active?.index == _currentIndex ? _active?.player : null;
PlayerPort? get active {
final slot = _active;
if (_closed ||
slot == null ||
slot.retiring ||
slot.index != _currentIndex) {
return null;
}
return slot.player;
}
bool get loading => _loading;
bool get userWantsPlay => _userWantsPlay;
bool get canAutoAdvance => _mayPlay && !_loading && active != null;
@@ -99,8 +109,15 @@ class PlaybackSession extends ChangeNotifier {
/// Exposes only prepared slots so the adjacent page can mount its video texture
/// during a swipe without starting audio or registering history listeners.
PlayerPort? preparedPlayerAt(int index) {
if (_closed) return null;
for (final slot in [_active, _next]) {
if (slot?.index == index && slot!.prepared) return slot.player;
if (slot == null ||
slot.retiring ||
slot.index != index ||
!slot.prepared) {
continue;
}
return slot.player;
}
return null;
}
@@ -162,6 +179,11 @@ class PlaybackSession extends ChangeNotifier {
Future<void> _retire(_PlayerSlot? slot) async {
if (slot == null || !_live.contains(slot)) return;
slot.retiring = true;
final cleared = _active == slot || _next == slot;
if (_active == slot) _active = null;
if (_next == slot) _next = null;
if (cleared) _notify();
await waitForFrame?.call();
await slot.ready;
try {
await slot.player.pause();
+7 -1
View File
@@ -40,13 +40,16 @@ class PlayerLogic extends ChangeNotifier {
required this.pictureInPicture,
this.wallet,
this.downloads,
});
Future<void> Function()? waitForFrame,
}) : _waitForFrame =
waitForFrame ?? (() => WidgetsBinding.instance.endOfFrame);
final WatchHistoryRepository history;
final PlaybackRepository playback;
final AndroidPictureInPicture pictureInPicture;
final WalletController? wallet;
final DownloadController? downloads;
final Future<void> Function() _waitForFrame;
late PageController pages;
late PlaybackQueue queue;
@@ -220,6 +223,7 @@ class PlayerLogic extends ChangeNotifier {
prepare: preparePlayer,
activate: activatePlayer,
coordinator: coordinator,
waitForFrame: _waitForFrame,
);
}
@@ -307,6 +311,8 @@ class PlayerLogic extends ChangeNotifier {
session = nextSession;
nextSession.setRouteVisible(active && visibleIndices.isNotEmpty);
_notifyAfterFrameIfNeeded();
await _waitForFrame();
if (revision != feedRevision || !identical(session, nextSession)) return;
await previous.close();
if (revision != feedRevision || !identical(session, nextSession)) return;
_jumpToFeedPage(targetIndex);