fix: ensure view drop stop playback startup (#3875)

This commit is contained in:
Krzysztof Moch 2024-06-07 13:54:14 +02:00
parent 7133c96cac
commit ff1e24aaad
3 changed files with 26 additions and 5 deletions

View File

@ -258,6 +258,7 @@ public class ReactExoplayerView extends FrameLayout implements
private long lastBufferDuration = -1; private long lastBufferDuration = -1;
private long lastDuration = -1; private long lastDuration = -1;
private boolean viewHasDropped = false;
private void updateProgress() { private void updateProgress() {
if (player != null) { if (player != null) {
if (playerControlView != null && isPlayingAd() && controls) { if (playerControlView != null && isPlayingAd() && controls) {
@ -375,6 +376,8 @@ public class ReactExoplayerView extends FrameLayout implements
public void cleanUpResources() { public void cleanUpResources() {
stopPlayback(); stopPlayback();
themedReactContext.removeLifecycleEventListener(this); themedReactContext.removeLifecycleEventListener(this);
releasePlayer();
viewHasDropped = true;
} }
//BandwidthMeter.EventListener implementation //BandwidthMeter.EventListener implementation
@ -647,6 +650,9 @@ public class ReactExoplayerView extends FrameLayout implements
Activity activity = themedReactContext.getCurrentActivity(); Activity activity = themedReactContext.getCurrentActivity();
// This ensures all props have been settled, to avoid async racing conditions. // This ensures all props have been settled, to avoid async racing conditions.
mainRunnable = () -> { mainRunnable = () -> {
if (viewHasDropped) {
return;
}
try { try {
if (player == null) { if (player == null) {
// Initialize core configuration and listeners // Initialize core configuration and listeners
@ -658,7 +664,9 @@ public class ReactExoplayerView extends FrameLayout implements
ExecutorService es = Executors.newSingleThreadExecutor(); ExecutorService es = Executors.newSingleThreadExecutor();
es.execute(() -> { es.execute(() -> {
// DRM initialization must run on a different thread // DRM initialization must run on a different thread
if (viewHasDropped) {
return;
}
if (activity == null) { if (activity == null) {
DebugLog.e(TAG, "Failed to initialize Player!, null activity"); DebugLog.e(TAG, "Failed to initialize Player!, null activity");
eventEmitter.error("Failed to initialize Player!", new Exception("Current Activity is null!"), "1001"); eventEmitter.error("Failed to initialize Player!", new Exception("Current Activity is null!"), "1001");
@ -667,12 +675,15 @@ public class ReactExoplayerView extends FrameLayout implements
// Initialize handler to run on the main thread // Initialize handler to run on the main thread
activity.runOnUiThread(() -> { activity.runOnUiThread(() -> {
if (viewHasDropped) {
return;
}
try { try {
// Source initialization must run on the main thread // Source initialization must run on the main thread
initializePlayerSource(); initializePlayerSource();
} catch (Exception ex) { } catch (Exception ex) {
self.playerNeedsSource = true; self.playerNeedsSource = true;
DebugLog.e(TAG, "Failed to initialize Player!"); DebugLog.e(TAG, "Failed to initialize Player! 1");
DebugLog.e(TAG, ex.toString()); DebugLog.e(TAG, ex.toString());
ex.printStackTrace(); ex.printStackTrace();
self.eventEmitter.error(ex.toString(), ex, "1001"); self.eventEmitter.error(ex.toString(), ex, "1001");
@ -684,7 +695,7 @@ public class ReactExoplayerView extends FrameLayout implements
} }
} catch (Exception ex) { } catch (Exception ex) {
self.playerNeedsSource = true; self.playerNeedsSource = true;
DebugLog.e(TAG, "Failed to initialize Player!"); DebugLog.e(TAG, "Failed to initialize Player! 2");
DebugLog.e(TAG, ex.toString()); DebugLog.e(TAG, ex.toString());
ex.printStackTrace(); ex.printStackTrace();
eventEmitter.error(ex.toString(), ex, "1001"); eventEmitter.error(ex.toString(), ex, "1001");

View File

@ -61,11 +61,11 @@ class NowPlayingInfoCenterManager {
return return
} }
if let observer = observers[players.hashValue] { if let observer = observers[player.hashValue] {
observer.invalidate() observer.invalidate()
} }
observers.removeValue(forKey: players.hashValue) observers.removeValue(forKey: player.hashValue)
players.remove(player) players.remove(player)
if currentPlayer == player { if currentPlayer == player {

View File

@ -1241,10 +1241,19 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
// MARK: - Lifecycle // MARK: - Lifecycle
override func removeFromSuperview() { override func removeFromSuperview() {
self._player?.replaceCurrentItem(with: nil)
if let player = _player { if let player = _player {
player.pause() player.pause()
NowPlayingInfoCenterManager.shared.removePlayer(player: player) NowPlayingInfoCenterManager.shared.removePlayer(player: player)
} }
_playerItem = nil
_source = nil
_chapters = nil
_drm = nil
_textTracks = nil
_selectedTextTrackCriteria = nil
_selectedAudioTrackCriteria = nil
_presentingViewController = nil
_player = nil _player = nil
_resouceLoaderDelegate = nil _resouceLoaderDelegate = nil
@ -1252,6 +1261,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
#if USE_GOOGLE_IMA #if USE_GOOGLE_IMA
_imaAdsManager.releaseAds() _imaAdsManager.releaseAds()
_imaAdsManager = nil
#endif #endif
self.removePlayerLayer() self.removePlayerLayer()