Skip to content

Commit

Permalink
use a static react instance holder
Browse files Browse the repository at this point in the history
Reviewed By: astreet

Differential Revision: D2937867

fb-gh-sync-id: cdda79929fa5993b6ef159aa73922909017c2ded
shipit-source-id: cdda79929fa5993b6ef159aa73922909017c2ded
  • Loading branch information
foghina authored and facebook-github-bot-7 committed Feb 19, 2016
1 parent b516976 commit 19a1c4c
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ protected void onPause() {
overridePendingTransition(0, 0);

if (mReactInstanceManager != null) {
mReactInstanceManager.onPause();
mReactInstanceManager.onHostPause();
}
}

Expand All @@ -86,7 +86,7 @@ protected void onResume() {
mLifecycleState = LifecycleState.RESUMED;

if (mReactInstanceManager != null) {
mReactInstanceManager.onResume(this, this);
mReactInstanceManager.onHostResume(this, this);
}
}

Expand All @@ -96,7 +96,7 @@ protected void onDestroy() {
mDestroyCountDownLatch.countDown();

if (mReactInstanceManager != null) {
mReactInstanceManager.onDestroy();
mReactInstanceManager.destroy();
}
}

Expand All @@ -114,7 +114,7 @@ public void loadApp(String appKey, ReactInstanceSpecForTest spec, String bundleN

public void resetRootViewForScreenshotTests() {
if (mReactInstanceManager != null) {
mReactInstanceManager.onDestroy();
mReactInstanceManager.destroy();
mReactInstanceManager = null;
}
mReactRootView = new ReactRootView(this);
Expand Down Expand Up @@ -148,7 +148,7 @@ public void loadApp(
.setInitialLifecycleState(mLifecycleState);

mReactInstanceManager = builder.build();
mReactInstanceManager.onResume(this, this);
mReactInstanceManager.onHostResume(this, this);

Assertions.assertNotNull(mReactRootView).getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public void shutDownContext() {
@Override
public void run() {
if (contextToDestroy != null) {
contextToDestroy.onDestroy();
contextToDestroy.destroy();
}
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
* RESUMED
*/
public enum LifecycleState {

BEFORE_CREATE,
BEFORE_RESUME,
RESUMED,
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ protected void onPause() {
mLifecycleState = LifecycleState.BEFORE_RESUME;

if (mReactInstanceManager != null) {
mReactInstanceManager.onPause();
mReactInstanceManager.onHostPause();
}
}

Expand All @@ -161,7 +161,7 @@ protected void onResume() {
mLifecycleState = LifecycleState.RESUMED;

if (mReactInstanceManager != null) {
mReactInstanceManager.onResume(this, this);
mReactInstanceManager.onHostResume(this, this);
}
}

Expand All @@ -170,7 +170,7 @@ protected void onDestroy() {
super.onDestroy();

if (mReactInstanceManager != null) {
mReactInstanceManager.onDestroy();
mReactInstanceManager.destroy();

This comment has been minimized.

Copy link
@baoti

baoti Feb 20, 2016

Call mReactInstanceManager.onHostDestroy() ?

This comment has been minimized.

Copy link
@foghina

foghina Feb 22, 2016

Author Contributor

@baoti mReactInstanceManager.onHostDestroy() would only notify listeners of the destroyed host, but not actually teardown the JS context. Calling destroy() instead notifies listeners of both the host being destroyed and the react instance being destroyed, before tearing down the JS context & freeing up a bunch of resources. Since we're not reusing the react instance, this makes more sense.

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
* The lifecycle of the instance of {@link ReactInstanceManager} should be bound to the activity
* that owns the {@link ReactRootView} that is used to render react application using this
* instance manager (see {@link ReactRootView#startReactApplication}). It's required to pass
* owning activity's lifecycle events to the instance manager (see {@link #onPause},
* {@link #onDestroy} and {@link #onResume}).
* owning activity's lifecycle events to the instance manager (see {@link #onHostPause},
* {@link #onHostDestroy} and {@link #onHostResume}).
*
* Ideally, this would be an interface, but because of the API used by earlier versions, it has to
* have a static method, and so cannot (in Java < 8), be one.
Expand Down Expand Up @@ -84,22 +84,32 @@ public interface ReactInstanceEventListener {
* consume the event, mDefaultBackButtonImpl will be invoked at the end of the round trip to JS.
*/
public abstract void onBackPressed();
public abstract void onPause();

/**
* Call this from {@link Activity#onPause()}. This notifies any listening modules so they can do
* any necessary cleanup.
*/
public abstract void onHostPause();
/**
* Use this method when the activity resumes to enable invoking the back button directly from JS.
*
* This method retains an instance to provided mDefaultBackButtonImpl. Thus it's
* important to pass from the activity instance that owns this particular instance of {@link
* ReactInstanceManager}, so that once this instance receive {@link #onDestroy} event it will
* ReactInstanceManager}, so that once this instance receive {@link #onHostDestroy} event it will
* clear the reference to that defaultBackButtonImpl.
*
* @param defaultBackButtonImpl a {@link DefaultHardwareBackBtnHandler} from an Activity that owns
* this instance of {@link ReactInstanceManager}.
*/
public abstract void onResume(
public abstract void onHostResume(
Activity activity,
DefaultHardwareBackBtnHandler defaultBackButtonImpl);
public abstract void onDestroy();

/**
* Call this from {@link Activity#onDestroy()}. This notifies any listening modules so they can do
* any necessary cleanup.
*/
public abstract void onHostDestroy();
public abstract void onActivityResult(int requestCode, int resultCode, Intent data);
public abstract void showDevOptionsDialog();

Expand All @@ -125,6 +135,11 @@ public abstract void onResume(
*/
public abstract void detachRootView(ReactRootView rootView);

/**
* Destroy this React instance and the attached JS context.
*/
public abstract void destroy();

/**
* Uses configured {@link ReactPackage} instances to create all view managers
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;

import android.app.Activity;
import android.app.Application;
Expand Down Expand Up @@ -73,7 +71,18 @@
import com.facebook.soloader.SoLoader;
import com.facebook.systrace.Systrace;

import static com.facebook.react.bridge.ReactMarkerConstants.*;
import static com.facebook.react.bridge.ReactMarkerConstants.BUILD_JS_MODULE_CONFIG_END;
import static com.facebook.react.bridge.ReactMarkerConstants.BUILD_JS_MODULE_CONFIG_START;
import static com.facebook.react.bridge.ReactMarkerConstants.BUILD_NATIVE_MODULE_REGISTRY_END;
import static com.facebook.react.bridge.ReactMarkerConstants.BUILD_NATIVE_MODULE_REGISTRY_START;
import static com.facebook.react.bridge.ReactMarkerConstants.CREATE_CATALYST_INSTANCE_END;
import static com.facebook.react.bridge.ReactMarkerConstants.CREATE_CATALYST_INSTANCE_START;
import static com.facebook.react.bridge.ReactMarkerConstants.CREATE_REACT_CONTEXT_END;
import static com.facebook.react.bridge.ReactMarkerConstants.CREATE_REACT_CONTEXT_START;
import static com.facebook.react.bridge.ReactMarkerConstants.PROCESS_PACKAGES_END;
import static com.facebook.react.bridge.ReactMarkerConstants.PROCESS_PACKAGES_START;
import static com.facebook.react.bridge.ReactMarkerConstants.RUN_JS_BUNDLE_END;
import static com.facebook.react.bridge.ReactMarkerConstants.RUN_JS_BUNDLE_START;

/**
* This class is managing instances of {@link CatalystInstance}. It expose a way to configure
Expand All @@ -87,8 +96,8 @@
* The lifecycle of the instance of {@link ReactInstanceManagerImpl} should be bound to the activity
* that owns the {@link ReactRootView} that is used to render react application using this
* instance manager (see {@link ReactRootView#startReactApplication}). It's required to pass
* owning activity's lifecycle events to the instance manager (see {@link #onPause},
* {@link #onDestroy} and {@link #onResume}).
* owning activity's lifecycle events to the instance manager (see {@link #onHostPause},
* {@link #onHostDestroy} and {@link #onHostResume}).
*
* To instantiate an instance of this class use {@link #builder}.
*/
Expand Down Expand Up @@ -458,71 +467,116 @@ private void toggleElementInspector() {
}

@Override
public void onPause() {
public void onHostPause() {
UiThreadUtil.assertOnUiThread();

mLifecycleState = LifecycleState.BEFORE_RESUME;

mDefaultBackButtonImpl = null;
if (mUseDeveloperSupport) {
mDevSupportManager.setDevSupportEnabled(false);
}

moveToBeforeResumeLifecycleState();
mCurrentActivity = null;
if (mCurrentReactContext != null) {
mCurrentReactContext.onPause();
}
}

/**
* Use this method when the activity resumes to enable invoking the back button directly from JS.
*
* This method retains an instance to provided mDefaultBackButtonImpl. Thus it's
* important to pass from the activity instance that owns this particular instance of {@link
* ReactInstanceManagerImpl}, so that once this instance receive {@link #onDestroy} event it will
* ReactInstanceManagerImpl}, so that once this instance receive {@link #onHostDestroy} event it will
* clear the reference to that defaultBackButtonImpl.
*
* @param defaultBackButtonImpl a {@link DefaultHardwareBackBtnHandler} from an Activity that owns
* this instance of {@link ReactInstanceManagerImpl}.
*/
@Override
public void onResume(Activity activity, DefaultHardwareBackBtnHandler defaultBackButtonImpl) {
public void onHostResume(Activity activity, DefaultHardwareBackBtnHandler defaultBackButtonImpl) {
UiThreadUtil.assertOnUiThread();

mLifecycleState = LifecycleState.RESUMED;

mDefaultBackButtonImpl = defaultBackButtonImpl;
if (mUseDeveloperSupport) {
mDevSupportManager.setDevSupportEnabled(true);
}

mCurrentActivity = activity;
if (mCurrentReactContext != null) {
mCurrentReactContext.onResume(activity);
moveToResumedLifecycleState(false);
}

@Override
public void onHostDestroy() {
UiThreadUtil.assertOnUiThread();

if (mUseDeveloperSupport) {
mDevSupportManager.setDevSupportEnabled(false);
}

moveToBeforeCreateLifecycleState();
mCurrentActivity = null;
}

@Override
public void onDestroy() {
public void destroy() {
UiThreadUtil.assertOnUiThread();

if (mUseDeveloperSupport) {
mDevSupportManager.setDevSupportEnabled(false);
}

moveToBeforeCreateLifecycleState();

if (mReactContextInitAsyncTask != null) {
mReactContextInitAsyncTask.cancel(true);
}

mMemoryPressureRouter.destroy(mApplicationContext);
if (mUseDeveloperSupport) {
mDevSupportManager.setDevSupportEnabled(false);
}

if (mCurrentReactContext != null) {
mCurrentReactContext.onDestroy();
mCurrentReactContext.destroy();
mCurrentReactContext = null;
mHasStartedCreatingInitialContext = false;
}
mCurrentActivity = null;
}

private void moveToResumedLifecycleState(boolean force) {
if (mCurrentReactContext != null) {
// we currently don't have an onCreate callback so we call onResume for both transitions
if (force ||
mLifecycleState == LifecycleState.BEFORE_RESUME ||
mLifecycleState == LifecycleState.BEFORE_CREATE) {
mCurrentReactContext.onHostResume(mCurrentActivity);
}
}
mLifecycleState = LifecycleState.RESUMED;
}

private void moveToBeforeResumeLifecycleState() {
if (mCurrentReactContext != null) {
if (mLifecycleState == LifecycleState.BEFORE_CREATE) {
mCurrentReactContext.onHostResume(mCurrentActivity);
mCurrentReactContext.onHostPause();
} else if (mLifecycleState == LifecycleState.RESUMED) {
mCurrentReactContext.onHostPause();
}
}
mLifecycleState = LifecycleState.BEFORE_RESUME;
}

private void moveToBeforeCreateLifecycleState() {
if (mCurrentReactContext != null) {
if (mLifecycleState == LifecycleState.RESUMED) {
mCurrentReactContext.onHostPause();
mLifecycleState = LifecycleState.BEFORE_RESUME;
}
if (mLifecycleState == LifecycleState.BEFORE_RESUME) {
mCurrentReactContext.onHostDestroy();
}
}
mLifecycleState = LifecycleState.BEFORE_CREATE;
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (mCurrentReactContext != null) {
Expand Down Expand Up @@ -657,7 +711,7 @@ private void setupReactContext(ReactApplicationContext reactContext) {
catalystInstance.initialize();
mDevSupportManager.onNewReactContextCreated(reactContext);
mMemoryPressureRouter.onNewReactContextCreated(reactContext);
moveReactContextToCurrentLifecycleState(reactContext);
moveReactContextToCurrentLifecycleState();

for (ReactRootView rootView : mAttachedRootViews) {
attachMeasuredRootViewToInstance(rootView, catalystInstance);
Expand Down Expand Up @@ -706,12 +760,12 @@ private void detachViewFromInstance(
private void tearDownReactContext(ReactContext reactContext) {
UiThreadUtil.assertOnUiThread();
if (mLifecycleState == LifecycleState.RESUMED) {
reactContext.onPause();
reactContext.onHostPause();
}
for (ReactRootView rootView : mAttachedRootViews) {
detachViewFromInstance(rootView, reactContext.getCatalystInstance());
}
reactContext.onDestroy();
reactContext.destroy();
mDevSupportManager.onReactInstanceDestroyed(reactContext);
mMemoryPressureRouter.onReactInstanceDestroyed();
}
Expand Down Expand Up @@ -831,9 +885,9 @@ private void processPackage(
}
}

private void moveReactContextToCurrentLifecycleState(ReactApplicationContext reactContext) {
private void moveReactContextToCurrentLifecycleState() {
if (mLifecycleState == LifecycleState.RESUMED) {
reactContext.onResume(mCurrentActivity);
moveToResumedLifecycleState(true);
}
}
}
Loading

0 comments on commit 19a1c4c

Please sign in to comment.