Detangle destroy and create accesses
Differential Revision: D5823786 fbshipit-source-id: d6a6e29b856361a6b1d5ab48397607a844b5ab53
This commit is contained in:
parent
628cbe170b
commit
6334ed2ff3
|
@ -137,13 +137,18 @@ public class ReactInstanceManager {
|
||||||
private final DevSupportManager mDevSupportManager;
|
private final DevSupportManager mDevSupportManager;
|
||||||
private final boolean mUseDeveloperSupport;
|
private final boolean mUseDeveloperSupport;
|
||||||
private final @Nullable NotThreadSafeBridgeIdleDebugListener mBridgeIdleDebugListener;
|
private final @Nullable NotThreadSafeBridgeIdleDebugListener mBridgeIdleDebugListener;
|
||||||
|
private final Object mReactContextLock = new Object();
|
||||||
private @Nullable volatile ReactContext mCurrentReactContext;
|
private @Nullable volatile ReactContext mCurrentReactContext;
|
||||||
private final Context mApplicationContext;
|
private final Context mApplicationContext;
|
||||||
private @Nullable @ThreadConfined(UI) DefaultHardwareBackBtnHandler mDefaultBackButtonImpl;
|
private @Nullable @ThreadConfined(UI) DefaultHardwareBackBtnHandler mDefaultBackButtonImpl;
|
||||||
private @Nullable Activity mCurrentActivity;
|
private @Nullable Activity mCurrentActivity;
|
||||||
private final Collection<ReactInstanceEventListener> mReactInstanceEventListeners =
|
private final Collection<ReactInstanceEventListener> mReactInstanceEventListeners =
|
||||||
Collections.synchronizedSet(new HashSet<ReactInstanceEventListener>());
|
Collections.synchronizedSet(new HashSet<ReactInstanceEventListener>());
|
||||||
|
// Identifies whether the instance manager is or soon will be initialized (on background thread)
|
||||||
private volatile boolean mHasStartedCreatingInitialContext = false;
|
private volatile boolean mHasStartedCreatingInitialContext = false;
|
||||||
|
// Identifies whether the insance manager destroy function is in process,
|
||||||
|
// while true any spawned create thread should wait for proper clean up before initializing
|
||||||
|
private volatile Boolean mHasStartedDestroying = false;
|
||||||
private final UIImplementationProvider mUIImplementationProvider;
|
private final UIImplementationProvider mUIImplementationProvider;
|
||||||
private final MemoryPressureRouter mMemoryPressureRouter;
|
private final MemoryPressureRouter mMemoryPressureRouter;
|
||||||
private final @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
|
private final @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
|
||||||
|
@ -473,13 +478,13 @@ public class ReactInstanceManager {
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
UiThreadUtil.assertOnUiThread();
|
UiThreadUtil.assertOnUiThread();
|
||||||
ReactContext reactContext = mCurrentReactContext;
|
ReactContext reactContext = mCurrentReactContext;
|
||||||
if (mCurrentReactContext == null) {
|
if (reactContext == null) {
|
||||||
// Invoke without round trip to JS.
|
// Invoke without round trip to JS.
|
||||||
FLog.w(ReactConstants.TAG, "Instance detached from instance manager");
|
FLog.w(ReactConstants.TAG, "Instance detached from instance manager");
|
||||||
invokeDefaultOnBackPressed();
|
invokeDefaultOnBackPressed();
|
||||||
} else {
|
} else {
|
||||||
DeviceEventManagerModule deviceEventManagerModule =
|
DeviceEventManagerModule deviceEventManagerModule =
|
||||||
Assertions.assertNotNull(reactContext).getNativeModule(DeviceEventManagerModule.class);
|
reactContext.getNativeModule(DeviceEventManagerModule.class);
|
||||||
deviceEventManagerModule.emitHardwareBackPressed();
|
deviceEventManagerModule.emitHardwareBackPressed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -497,7 +502,8 @@ public class ReactInstanceManager {
|
||||||
@ThreadConfined(UI)
|
@ThreadConfined(UI)
|
||||||
public void onNewIntent(Intent intent) {
|
public void onNewIntent(Intent intent) {
|
||||||
UiThreadUtil.assertOnUiThread();
|
UiThreadUtil.assertOnUiThread();
|
||||||
if (mCurrentReactContext == null) {
|
ReactContext currentContext = getCurrentReactContext();
|
||||||
|
if (currentContext == null) {
|
||||||
FLog.w(ReactConstants.TAG, "Instance detached from instance manager");
|
FLog.w(ReactConstants.TAG, "Instance detached from instance manager");
|
||||||
} else {
|
} else {
|
||||||
String action = intent.getAction();
|
String action = intent.getAction();
|
||||||
|
@ -505,18 +511,18 @@ public class ReactInstanceManager {
|
||||||
|
|
||||||
if (Intent.ACTION_VIEW.equals(action) && uri != null) {
|
if (Intent.ACTION_VIEW.equals(action) && uri != null) {
|
||||||
DeviceEventManagerModule deviceEventManagerModule =
|
DeviceEventManagerModule deviceEventManagerModule =
|
||||||
Assertions.assertNotNull(mCurrentReactContext)
|
currentContext.getNativeModule(DeviceEventManagerModule.class);
|
||||||
.getNativeModule(DeviceEventManagerModule.class);
|
|
||||||
deviceEventManagerModule.emitNewIntentReceived(uri);
|
deviceEventManagerModule.emitNewIntentReceived(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
mCurrentReactContext.onNewIntent(mCurrentActivity, intent);
|
currentContext.onNewIntent(mCurrentActivity, intent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void toggleElementInspector() {
|
private void toggleElementInspector() {
|
||||||
if (mCurrentReactContext != null) {
|
ReactContext currentContext = getCurrentReactContext();
|
||||||
mCurrentReactContext
|
if (currentContext != null) {
|
||||||
|
currentContext
|
||||||
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
||||||
.emit("toggleElementInspector", null);
|
.emit("toggleElementInspector", null);
|
||||||
}
|
}
|
||||||
|
@ -623,6 +629,8 @@ public class ReactInstanceManager {
|
||||||
UiThreadUtil.assertOnUiThread();
|
UiThreadUtil.assertOnUiThread();
|
||||||
PrinterHolder.getPrinter().logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: Destroy");
|
PrinterHolder.getPrinter().logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: Destroy");
|
||||||
|
|
||||||
|
mHasStartedDestroying = true;
|
||||||
|
|
||||||
if (mUseDeveloperSupport) {
|
if (mUseDeveloperSupport) {
|
||||||
mDevSupportManager.setDevSupportEnabled(false);
|
mDevSupportManager.setDevSupportEnabled(false);
|
||||||
mDevSupportManager.stopInspector();
|
mDevSupportManager.stopInspector();
|
||||||
|
@ -631,54 +639,62 @@ public class ReactInstanceManager {
|
||||||
moveToBeforeCreateLifecycleState();
|
moveToBeforeCreateLifecycleState();
|
||||||
|
|
||||||
if (mCreateReactContextThread != null) {
|
if (mCreateReactContextThread != null) {
|
||||||
mCreateReactContextThread.interrupt();
|
|
||||||
mCreateReactContextThread = null;
|
mCreateReactContextThread = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
mMemoryPressureRouter.destroy(mApplicationContext);
|
mMemoryPressureRouter.destroy(mApplicationContext);
|
||||||
|
|
||||||
if (mCurrentReactContext != null) {
|
synchronized (mReactContextLock) {
|
||||||
mCurrentReactContext.destroy();
|
if (mCurrentReactContext != null) {
|
||||||
mCurrentReactContext = null;
|
mCurrentReactContext.destroy();
|
||||||
mHasStartedCreatingInitialContext = false;
|
mCurrentReactContext = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
mHasStartedCreatingInitialContext = false;
|
||||||
mCurrentActivity = null;
|
mCurrentActivity = null;
|
||||||
|
|
||||||
ResourceDrawableIdHelper.getInstance().clear();
|
ResourceDrawableIdHelper.getInstance().clear();
|
||||||
|
mHasStartedDestroying = false;
|
||||||
|
synchronized (mHasStartedDestroying) {
|
||||||
|
mHasStartedDestroying.notifyAll();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void moveToResumedLifecycleState(boolean force) {
|
private synchronized void moveToResumedLifecycleState(boolean force) {
|
||||||
if (mCurrentReactContext != null) {
|
ReactContext currentContext = getCurrentReactContext();
|
||||||
|
if (currentContext != null) {
|
||||||
// we currently don't have an onCreate callback so we call onResume for both transitions
|
// we currently don't have an onCreate callback so we call onResume for both transitions
|
||||||
if (force ||
|
if (force ||
|
||||||
mLifecycleState == LifecycleState.BEFORE_RESUME ||
|
mLifecycleState == LifecycleState.BEFORE_RESUME ||
|
||||||
mLifecycleState == LifecycleState.BEFORE_CREATE) {
|
mLifecycleState == LifecycleState.BEFORE_CREATE) {
|
||||||
mCurrentReactContext.onHostResume(mCurrentActivity);
|
currentContext.onHostResume(mCurrentActivity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mLifecycleState = LifecycleState.RESUMED;
|
mLifecycleState = LifecycleState.RESUMED;
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void moveToBeforeResumeLifecycleState() {
|
private synchronized void moveToBeforeResumeLifecycleState() {
|
||||||
if (mCurrentReactContext != null) {
|
ReactContext currentContext = getCurrentReactContext();
|
||||||
|
if (currentContext != null) {
|
||||||
if (mLifecycleState == LifecycleState.BEFORE_CREATE) {
|
if (mLifecycleState == LifecycleState.BEFORE_CREATE) {
|
||||||
mCurrentReactContext.onHostResume(mCurrentActivity);
|
currentContext.onHostResume(mCurrentActivity);
|
||||||
mCurrentReactContext.onHostPause();
|
currentContext.onHostPause();
|
||||||
} else if (mLifecycleState == LifecycleState.RESUMED) {
|
} else if (mLifecycleState == LifecycleState.RESUMED) {
|
||||||
mCurrentReactContext.onHostPause();
|
currentContext.onHostPause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mLifecycleState = LifecycleState.BEFORE_RESUME;
|
mLifecycleState = LifecycleState.BEFORE_RESUME;
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void moveToBeforeCreateLifecycleState() {
|
private synchronized void moveToBeforeCreateLifecycleState() {
|
||||||
if (mCurrentReactContext != null) {
|
ReactContext currentContext = getCurrentReactContext();
|
||||||
|
if (currentContext != null) {
|
||||||
if (mLifecycleState == LifecycleState.RESUMED) {
|
if (mLifecycleState == LifecycleState.RESUMED) {
|
||||||
mCurrentReactContext.onHostPause();
|
currentContext.onHostPause();
|
||||||
mLifecycleState = LifecycleState.BEFORE_RESUME;
|
mLifecycleState = LifecycleState.BEFORE_RESUME;
|
||||||
}
|
}
|
||||||
if (mLifecycleState == LifecycleState.BEFORE_RESUME) {
|
if (mLifecycleState == LifecycleState.BEFORE_RESUME) {
|
||||||
mCurrentReactContext.onHostDestroy();
|
currentContext.onHostDestroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mLifecycleState = LifecycleState.BEFORE_CREATE;
|
mLifecycleState = LifecycleState.BEFORE_CREATE;
|
||||||
|
@ -692,8 +708,9 @@ public class ReactInstanceManager {
|
||||||
|
|
||||||
@ThreadConfined(UI)
|
@ThreadConfined(UI)
|
||||||
public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
|
public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
|
||||||
if (mCurrentReactContext != null) {
|
ReactContext currentContext = getCurrentReactContext();
|
||||||
mCurrentReactContext.onActivityResult(activity, requestCode, resultCode, data);
|
if (currentContext != null) {
|
||||||
|
currentContext.onActivityResult(activity, requestCode, resultCode, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -722,8 +739,9 @@ public class ReactInstanceManager {
|
||||||
|
|
||||||
// If react context is being created in the background, JS application will be started
|
// If react context is being created in the background, JS application will be started
|
||||||
// automatically when creation completes, as root view is part of the attached root view list.
|
// automatically when creation completes, as root view is part of the attached root view list.
|
||||||
if (mCreateReactContextThread == null && mCurrentReactContext != null) {
|
ReactContext currentContext = getCurrentReactContext();
|
||||||
attachRootViewToInstance(rootView, mCurrentReactContext.getCatalystInstance());
|
if (mCreateReactContextThread == null && currentContext != null) {
|
||||||
|
attachRootViewToInstance(rootView, currentContext.getCatalystInstance());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -736,8 +754,9 @@ public class ReactInstanceManager {
|
||||||
public void detachRootView(ReactRootView rootView) {
|
public void detachRootView(ReactRootView rootView) {
|
||||||
UiThreadUtil.assertOnUiThread();
|
UiThreadUtil.assertOnUiThread();
|
||||||
if (mAttachedRootViews.remove(rootView)) {
|
if (mAttachedRootViews.remove(rootView)) {
|
||||||
if (mCurrentReactContext != null && mCurrentReactContext.hasActiveCatalystInstance()) {
|
ReactContext currentContext = getCurrentReactContext();
|
||||||
detachViewFromInstance(rootView, mCurrentReactContext.getCatalystInstance());
|
if (currentContext != null && currentContext.hasActiveCatalystInstance()) {
|
||||||
|
detachViewFromInstance(rootView, currentContext.getCatalystInstance());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -777,7 +796,9 @@ public class ReactInstanceManager {
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public @Nullable ReactContext getCurrentReactContext() {
|
public @Nullable ReactContext getCurrentReactContext() {
|
||||||
return mCurrentReactContext;
|
synchronized (mReactContextLock) {
|
||||||
|
return mCurrentReactContext;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public LifecycleState getLifecycleState() {
|
public LifecycleState getLifecycleState() {
|
||||||
|
@ -828,14 +849,28 @@ public class ReactInstanceManager {
|
||||||
private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams) {
|
private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams) {
|
||||||
Log.d(ReactConstants.TAG, "ReactInstanceManager.runCreateReactContextOnNewThread()");
|
Log.d(ReactConstants.TAG, "ReactInstanceManager.runCreateReactContextOnNewThread()");
|
||||||
UiThreadUtil.assertOnUiThread();
|
UiThreadUtil.assertOnUiThread();
|
||||||
if (mCurrentReactContext != null) {
|
synchronized (mReactContextLock) {
|
||||||
tearDownReactContext(mCurrentReactContext);
|
if (mCurrentReactContext != null) {
|
||||||
mCurrentReactContext = null;
|
tearDownReactContext(mCurrentReactContext);
|
||||||
|
mCurrentReactContext = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mCreateReactContextThread = new Thread(new Runnable() {
|
mCreateReactContextThread = new Thread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
synchronized (ReactInstanceManager.this.mHasStartedDestroying) {
|
||||||
|
while (ReactInstanceManager.this.mHasStartedDestroying) {
|
||||||
|
try {
|
||||||
|
ReactInstanceManager.this.mHasStartedDestroying.wait();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// As destroy() may have run and set this to false, ensure that it is true before we create
|
||||||
|
mHasStartedCreatingInitialContext = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
|
Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
|
||||||
final ReactApplicationContext reactApplicationContext = createReactContext(
|
final ReactApplicationContext reactApplicationContext = createReactContext(
|
||||||
|
@ -879,7 +914,9 @@ public class ReactInstanceManager {
|
||||||
ReactMarker.logMarker(PRE_SETUP_REACT_CONTEXT_END);
|
ReactMarker.logMarker(PRE_SETUP_REACT_CONTEXT_END);
|
||||||
ReactMarker.logMarker(SETUP_REACT_CONTEXT_START);
|
ReactMarker.logMarker(SETUP_REACT_CONTEXT_START);
|
||||||
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "setupReactContext");
|
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "setupReactContext");
|
||||||
mCurrentReactContext = Assertions.assertNotNull(reactContext);
|
synchronized (mReactContextLock) {
|
||||||
|
mCurrentReactContext = Assertions.assertNotNull(reactContext);
|
||||||
|
}
|
||||||
CatalystInstance catalystInstance =
|
CatalystInstance catalystInstance =
|
||||||
Assertions.assertNotNull(reactContext.getCatalystInstance());
|
Assertions.assertNotNull(reactContext.getCatalystInstance());
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue