From 46a28e5460b476817a6844deaa16852aa9261f06 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Sat, 19 Oct 2019 02:27:35 -0700 Subject: [PATCH] AppStateModule should verify that Catalyst is alive before getting a JS module Summary: AppStateModule can be called indirectly when the ReactContext is torn down. Trying to get a JS module at this time will result in a crash if the ReactContext has already torn down Catalyst. Check explicitly that Catalyst is still alive before trying to emit an event to JS via some JS module. Changelog: [Internal] Reviewed By: ejanzer, mdvacca Differential Revision: D17969056 fbshipit-source-id: dd446de57280e588a73f3e228bac82b3d67ecdc0 --- .../modules/appstate/AppStateModule.java | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) 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 68c8857ec0..9937b2f729 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,23 +7,28 @@ 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; import java.util.Map; +import javax.annotation.Nullable; @ReactModule(name = AppStateModule.NAME) public class AppStateModule extends ReactContextBaseJavaModule implements LifecycleEventListener, WindowFocusChangeListener { + public static final String TAG = AppStateModule.class.getSimpleName(); public static final String NAME = "AppState"; @@ -81,9 +86,7 @@ public class AppStateModule extends ReactContextBaseJavaModule @Override public void onWindowFocusChange(boolean hasFocus) { - getReactApplicationContext() - .getJSModule(RCTDeviceEventEmitter.class) - .emit("appStateFocusChange", hasFocus); + sendEvent("appStateFocusChange", hasFocus); } private WritableMap createAppStateEventMap() { @@ -92,9 +95,26 @@ public class AppStateModule extends ReactContextBaseJavaModule return appState; } + private void sendEvent(String eventName, @Nullable Object data) { + ReactApplicationContext reactApplicationContext = getReactApplicationContext(); + + if (reactApplicationContext.hasActiveCatalystInstance()) { + 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)); + } + } + } + private void sendAppStateChangeEvent() { - getReactApplicationContext() - .getJSModule(RCTDeviceEventEmitter.class) - .emit("appStateDidChange", createAppStateEventMap()); + sendEvent("appStateDidChange", createAppStateEventMap()); } }