diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContextBaseJavaModule.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContextBaseJavaModule.java index bd796ae26db..33e95765681 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContextBaseJavaModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContextBaseJavaModule.java @@ -7,9 +7,14 @@ package com.facebook.react.bridge; +import static com.facebook.infer.annotation.ThreadConfined.ANY; + import android.app.Activity; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.facebook.common.logging.FLog; +import com.facebook.infer.annotation.ThreadConfined; +import com.facebook.react.common.build.ReactBuildConfig; /** * Base class for Catalyst native modules that require access to the {@link ReactContext} instance. @@ -22,11 +27,41 @@ public abstract class ReactContextBaseJavaModule extends BaseJavaModule { mReactApplicationContext = reactContext; } - /** Subclasses can use this method to access catalyst context passed as a constructor */ + /** Subclasses can use this method to access catalyst context passed as a constructor. */ protected final ReactApplicationContext getReactApplicationContext() { return mReactApplicationContext; } + /** + * Subclasses can use this method to access catalyst context passed as a constructor. Use this + * version to check that the underlying CatalystInstance is active before returning, and + * automatically have SoftExceptions or debug information logged for you. Consider using this + * whenever calling ReactApplicationContext methods that require the Catalyst instance be alive. + * + *
This can return null at any time, but especially during teardown methods it's + * possible/likely. + * + *
Threading implications have not been analyzed fully yet, so assume this method is not
+ * thread-safe.
+ */
+ @ThreadConfined(ANY)
+ protected @Nullable final ReactApplicationContext getReactApplicationContextIfActiveOrWarn(
+ String tag, String reason) {
+ if (mReactApplicationContext.hasActiveCatalystInstance()) {
+ return mReactApplicationContext;
+ }
+
+ // We want to collect data about how often this happens, but SoftExceptions will cause a crash
+ // in debug mode, which isn't usually desirable.
+ String msg = "Catalyst Instance has already disappeared: " + reason;
+ if (ReactBuildConfig.DEBUG) {
+ FLog.w(tag, msg);
+ } else {
+ ReactSoftException.logSoftException(tag, new RuntimeException(msg));
+ }
+ return null;
+ }
+
/**
* Get the activity to which this context is currently attached, or {@code null} if not attached.
*
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java
index 9937b2f7291..e4c5f40dd55 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java
@@ -7,18 +7,15 @@
package com.facebook.react.modules.appstate;
-import android.util.Log;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
-import com.facebook.react.bridge.ReactSoftException;
import com.facebook.react.bridge.WindowFocusChangeListener;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.common.LifecycleState;
-import com.facebook.react.common.build.ReactBuildConfig;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter;
import java.util.HashMap;
@@ -96,21 +93,12 @@ public class AppStateModule extends ReactContextBaseJavaModule
}
private void sendEvent(String eventName, @Nullable Object data) {
- ReactApplicationContext reactApplicationContext = getReactApplicationContext();
+ ReactApplicationContext reactApplicationContext =
+ getReactApplicationContextIfActiveOrWarn(
+ TAG, "sendAppStateChangeEvent: trying to update app state");
- if (reactApplicationContext.hasActiveCatalystInstance()) {
+ if (reactApplicationContext != null) {
reactApplicationContext.getJSModule(RCTDeviceEventEmitter.class).emit(eventName, data);
- } else {
- // We want to collect data about how often this happens, but this will cause a crash
- // in debug, which isn't desirable.
- String msg =
- "sendAppStateChangeEvent: trying to update app state when Catalyst Instance has already disappeared: "
- + eventName;
- if (ReactBuildConfig.DEBUG) {
- Log.e(AppStateModule.TAG, msg);
- } else {
- ReactSoftException.logSoftException(AppStateModule.TAG, new RuntimeException(msg));
- }
}
}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java
index 6684d9e33b5..d1e3d6a6c76 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java
@@ -7,22 +7,18 @@
package com.facebook.react.modules.websocket;
-import android.util.Log;
import androidx.annotation.Nullable;
import com.facebook.common.logging.FLog;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
-import com.facebook.react.bridge.ReactSoftException;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableMapKeySetIterator;
import com.facebook.react.bridge.ReadableType;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.common.ReactConstants;
-import com.facebook.react.common.build.ReactBuildConfig;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.facebook.react.modules.network.ForwardingCookieHandler;
@@ -43,6 +39,8 @@ import okio.ByteString;
@ReactModule(name = WebSocketModule.NAME, hasConstants = false)
public final class WebSocketModule extends ReactContextBaseJavaModule {
+ public static final String TAG = WebSocketModule.class.getSimpleName();
+
public static final String NAME = "WebSocketModule";
public interface ContentHandler {
@@ -54,30 +52,22 @@ public final class WebSocketModule extends ReactContextBaseJavaModule {
private final Map