diff --git a/Example/yarn.lock b/Example/yarn.lock index c0dbdc9..36b1a8f 100644 --- a/Example/yarn.lock +++ b/Example/yarn.lock @@ -1470,7 +1470,7 @@ "@jridgewell/sourcemap-codec" "^1.4.14" "@jwplayer/jwplayer-react-native@../../jwplayer-react-native": - version "1.3.1" + version "1.3.2" dependencies: lodash.isequalwith "^4.4.0" diff --git a/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerView.java b/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerView.java index e6f88b3..95f8f7b 100755 --- a/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerView.java +++ b/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerView.java @@ -243,6 +243,9 @@ public class RNJWPlayerView extends RelativeLayout implements // Add completion handler field PlaylistItemDecision itemUpdatePromise = null; + // Flag to prevent race conditions during player destruction + private volatile boolean isDestroying = false; + private void doBindService() { if (mMediaServiceController != null) { if (!isBackgroundAudioServiceRunning()) { @@ -380,7 +383,22 @@ public Lifecycle getLifecycle() { // } public void destroyPlayer() { - if (mPlayer != null) { + if (mPlayer != null && !isDestroying) { + isDestroying = true; + + // Disable touch events immediately to prevent race conditions + if (mPlayerView != null) { + Handler mainHandler = new Handler(Looper.getMainLooper()); + mainHandler.post(() -> { + if (mPlayerView != null) { + mPlayerView.setClickable(false); + mPlayerView.setFocusable(false); + mPlayerView.setEnabled(false); + mPlayerView.setOnTouchListener(null); + } + }); + } + unRegisterReceiver(); // If we are casting we need to break the cast session as there is no simple @@ -480,6 +498,8 @@ public void destroyPlayer() { audioManager = null; doUnbindService(); + + isDestroying = false; // Reset flag for potential reuse } } diff --git a/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerViewManager.java b/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerViewManager.java index 578c5e4..915b365 100644 --- a/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerViewManager.java +++ b/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerViewManager.java @@ -1,5 +1,7 @@ package com.jwplayer.rnjwplayer; +import android.util.Log; + import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.common.MapBuilder; @@ -43,7 +45,14 @@ public void setControls(RNJWPlayerView view, Boolean controls) { if (view == null || view.mPlayerView == null) { return; } - view.mPlayerView.getPlayer().setControls(controls); + // Add null check for getPlayer() to prevent crashes + try { + if (view.mPlayerView.getPlayer() != null) { + view.mPlayerView.getPlayer().setControls(controls); + } + } catch (Exception e) { + Log.w(TAG, "Error setting controls: " + e.getMessage()); + } } /** @@ -58,8 +67,15 @@ public void recreatePlayerWithConfig(RNJWPlayerView view, ReadableMap config) { if (view == null || view.mPlayerView == null) { return; } - view.mPlayerView.getPlayer().stop(); - view.setConfig(config); + // Add null check for getPlayer() to prevent crashes + try { + if (view.mPlayerView.getPlayer() != null) { + view.mPlayerView.getPlayer().stop(); + } + view.setConfig(config); + } catch (Exception e) { + Log.w(TAG, "Error recreating player: " + e.getMessage()); + } } public Map getExportedCustomBubblingEventTypeConstants() {