Permalink
Browse files

add ReactFragmentActivity, share delegate with ReactActivity

Summary: Add FragmentActivity-based ReactFragmentActivity to support apps using the v4 support lib. Add delegate class to share implementation details between the new class and ReactActivity.

Reviewed By: astreet

Differential Revision: D3655428

fbshipit-source-id: d3ff916538e13b6f0d594bbb91555e322645e954
  • Loading branch information...
1 parent 0b5c612 commit 3c4fd42749e0079b0cf54e1106bf81c993f9d29a @foghina foghina committed with Facebook Github Bot 1 Aug 8, 2016
@@ -14,6 +14,7 @@ DEPS = [
react_native_dep('java/com/facebook/systrace:systrace'),
react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'),
react_native_dep('libraries/soloader/java/com/facebook/soloader:soloader'),
+ react_native_dep('third-party/android/support/v4:lib-support-v4'),
react_native_dep('third-party/java/infer-annotations:infer-annotations'),
react_native_dep('third-party/java/jsr-305:jsr-305'),
]
@@ -9,21 +9,11 @@
package com.facebook.react;
-import javax.annotation.Nullable;
-
-import java.util.List;
-
import android.app.Activity;
import android.content.Intent;
-import android.os.Build;
import android.os.Bundle;
-import android.provider.Settings;
import android.view.KeyEvent;
-import android.widget.Toast;
-import com.facebook.common.logging.FLog;
-import com.facebook.react.common.ReactConstants;
-import com.facebook.react.devsupport.DoubleTapReloadRecognizer;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.modules.core.PermissionAwareActivity;
import com.facebook.react.modules.core.PermissionListener;
@@ -34,24 +24,10 @@
public abstract class ReactActivity extends Activity
implements DefaultHardwareBackBtnHandler, PermissionAwareActivity {
- private static final String REDBOX_PERMISSION_MESSAGE =
- "Overlay permissions needs to be granted in order for react native apps to run in dev mode";
+ private final ReactActivityDelegate mDelegate;
- private @Nullable PermissionListener mPermissionListener;
- private @Nullable ReactInstanceManager mReactInstanceManager;
- private @Nullable ReactRootView mReactRootView;
- private DoubleTapReloadRecognizer mDoubleTapReloadRecognizer;
- private boolean mDoRefresh = false;
-
- /**
- * Returns the launchOptions which will be passed to the {@link ReactInstanceManager}
- * when the application is started. By default, this will return null and an empty
- * object will be passed to your top level component as its initial props.
- * If your React Native application requires props set outside of JS, override
- * this method to return the Android.os.Bundle of your desired initial props.
- */
- protected @Nullable Bundle getLaunchOptions() {
- return null;
+ protected ReactActivity() {
+ mDelegate = createReactActivityDelegate();
}
/**
@@ -62,112 +38,49 @@
protected abstract String getMainComponentName();
/**
- * A subclass may override this method if it needs to use a custom {@link ReactRootView}.
+ * Called at construction time, override if you have a custom delegate implementation.
*/
- protected ReactRootView createRootView() {
- return new ReactRootView(this);
- }
-
- /**
- * Get the {@link ReactNativeHost} used by this app. By default, assumes {@link #getApplication()}
- * is an instance of {@link ReactApplication} and calls
- * {@link ReactApplication#getReactNativeHost()}. Override this method if your application class
- * does not implement {@code ReactApplication} or you simply have a different mechanism for
- * storing a {@code ReactNativeHost}, e.g. as a static field somewhere.
- */
- protected ReactNativeHost getReactNativeHost() {
- return ((ReactApplication) getApplication()).getReactNativeHost();
- }
-
- /**
- * Get whether developer support should be enabled or not. By default this delegates to
- * {@link ReactNativeHost#getUseDeveloperSupport()}. Override this method if your application
- * class does not implement {@code ReactApplication} or you simply have a different logic for
- * determining this (default just checks {@code BuildConfig}).
- */
- protected boolean getUseDeveloperSupport() {
- return ((ReactApplication) getApplication()).getReactNativeHost().getUseDeveloperSupport();
+ protected ReactActivityDelegate createReactActivityDelegate() {
+ return new ReactActivityDelegate(this, getMainComponentName());
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
- if (getUseDeveloperSupport() && Build.VERSION.SDK_INT >= 23) {
- // Get permission to show redbox in dev builds.
- if (!Settings.canDrawOverlays(this)) {
- Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
- startActivity(serviceIntent);
- FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE);
- Toast.makeText(this, REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show();
- }
- }
-
- mReactRootView = createRootView();
- mReactRootView.startReactApplication(
- getReactNativeHost().getReactInstanceManager(),
- getMainComponentName(),
- getLaunchOptions());
- setContentView(mReactRootView);
- mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
+ mDelegate.onCreate(savedInstanceState);
}
@Override
protected void onPause() {
super.onPause();
-
- if (getReactNativeHost().hasInstance()) {
- getReactNativeHost().getReactInstanceManager().onHostPause();
- }
+ mDelegate.onPause();
}
@Override
protected void onResume() {
super.onResume();
-
- if (getReactNativeHost().hasInstance()) {
- getReactNativeHost().getReactInstanceManager().onHostResume(this, this);
- }
+ mDelegate.onResume();
}
@Override
protected void onDestroy() {
super.onDestroy();
-
- if (mReactRootView != null) {
- mReactRootView.unmountReactApplication();
- mReactRootView = null;
- }
- getReactNativeHost().clear();
+ mDelegate.onDestroy();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (getReactNativeHost().hasInstance()) {
- getReactNativeHost().getReactInstanceManager()
- .onActivityResult(requestCode, resultCode, data);
- }
+ mDelegate.onActivityResult(requestCode, resultCode, data);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (getReactNativeHost().hasInstance() && getUseDeveloperSupport()) {
- if (keyCode == KeyEvent.KEYCODE_MENU) {
- getReactNativeHost().getReactInstanceManager().showDevOptionsDialog();
- return true;
- }
- if (mDoubleTapReloadRecognizer.didDoubleTapR(keyCode, getCurrentFocus())) {
- getReactNativeHost().getReactInstanceManager().getDevSupportManager().handleReloadJS();
- }
- }
- return super.onKeyUp(keyCode, event);
+ return mDelegate.onKeyUp(keyCode, event) || super.onKeyUp(keyCode, event);
}
@Override
public void onBackPressed() {
- if (getReactNativeHost().hasInstance()) {
- getReactNativeHost().getReactInstanceManager().onBackPressed();
- } else {
+ if (!mDelegate.onBackPressed()) {
super.onBackPressed();
}
}
@@ -179,30 +92,32 @@ public void invokeDefaultOnBackPressed() {
@Override
public void onNewIntent(Intent intent) {
- if (getReactNativeHost().hasInstance()) {
- getReactNativeHost().getReactInstanceManager().onNewIntent(intent);
- } else {
+ if (!mDelegate.onNewIntent(intent)) {
super.onNewIntent(intent);
}
}
@Override
public void requestPermissions(
- String[] permissions,
- int requestCode,
- PermissionListener listener) {
- mPermissionListener = listener;
- this.requestPermissions(permissions, requestCode);
+ String[] permissions,
+ int requestCode,
+ PermissionListener listener) {
+ mDelegate.requestPermissions(permissions, requestCode, listener);
}
@Override
public void onRequestPermissionsResult(
- int requestCode,
- String[] permissions,
- int[] grantResults) {
- if (mPermissionListener != null &&
- mPermissionListener.onRequestPermissionsResult(requestCode, permissions, grantResults)) {
- mPermissionListener = null;
- }
+ int requestCode,
+ String[] permissions,
+ int[] grantResults) {
+ mDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ }
+
+ protected final ReactNativeHost getReactNativeHost() {
+ return mDelegate.getReactNativeHost();
+ }
+
+ protected final ReactInstanceManager getReactInstanceManager() {
+ return mDelegate.getReactInstanceManager();
}
}
Oops, something went wrong.

3 comments on commit 3c4fd42

@rozele
Contributor
rozele commented on 3c4fd42 Aug 10, 2016

FYI, this breaks the UIExplorer for Android.

@rigdern
Contributor

@astreet @foghina Prior to this change, ReactActivity would throw away the ReactInstanceManager during onDestroy by calling getReactNativeHost().clear();. As of this change, this is no longer the case. Was this intentional?

I'm asking because I was about to submit a PR to enable apps to configure whether or not ReactActivity throws away the ReactInstanceManager. If this commit intentionally decoupled the lifetimes of the ReactActivity and the ReactInstanceManager, then my PR is no longer necessary.

@foghina
Contributor

Was this intentional?

Yep. This is why we introduced ReactNativeHost and ReactApplication -- to manage the react instance lifecycle at the application level, not the activity level. This enables a few things:

  1. Faster warm starts
  2. Multiple activities sharing the same react instance
  3. (future) Running JS in the background (as a Service)
Please sign in to comment.