Skip to content

Commit

Permalink
Add first-class support to ReactInstanceManager for Activity-less usage
Browse files Browse the repository at this point in the history
Summary:
I'm not sure if we'll ever need to do more than this (probably!) but I want to have a specific option for Activity-less usage, so
that our logic in ReactInstanceManager and elsewhere is more clear. I want to be able to confidently assert that the Activity is present
and correct, or never present, depending on if this `requireActivity` flag is set; instead of adding else statements that imply "well, the Activity should be here, hope everything is okay" which feels hacky.

Doesn't change much for now, but it's an additional constraint in the RN Android codebase that we need to explicitly embed in code so that
we can point to it, and so that the logic is more clear.

Changelog: [Internal]

Reviewed By: javache, motiz88

Differential Revision: D30504616

fbshipit-source-id: d2abdb7c4765a16113c9517406cdbb8cf42822ff
  • Loading branch information
JoshuaGross authored and facebook-github-bot committed Aug 25, 2021
1 parent 5902152 commit 4841e1b
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -156,12 +156,14 @@ public interface ReactInstanceEventListener {
/* accessed from any thread */
private final JavaScriptExecutorFactory mJavaScriptExecutorFactory;

// See {@code ReactInstanceManagerBuilder} for description of all flags here.
private @Nullable List<String> mViewManagerNames = null;
private final @Nullable JSBundleLoader mBundleLoader;
private final @Nullable String mJSMainModulePath; /* path to JS bundle root on Metro */
private final List<ReactPackage> mPackages;
private final DevSupportManager mDevSupportManager;
private final boolean mUseDeveloperSupport;
private final boolean mRequireActivity;
private @Nullable ComponentNameResolverManager mComponentNameResolverManager;
private @Nullable RuntimeSchedulerManager mRuntimeSchedulerManager;
private final @Nullable NotThreadSafeBridgeIdleDebugListener mBridgeIdleDebugListener;
Expand Down Expand Up @@ -216,6 +218,7 @@ public static ReactInstanceManagerBuilder builder() {
@Nullable String jsMainModulePath,
List<ReactPackage> packages,
boolean useDeveloperSupport,
boolean requireActivity,
@Nullable NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener,
LifecycleState initialLifecycleState,
@Nullable UIImplementationProvider mUIImplementationProvider,
Expand All @@ -233,6 +236,7 @@ public static ReactInstanceManagerBuilder builder() {

DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(applicationContext);

// See {@code ReactInstanceManagerBuilder} for description of all flags here.
mApplicationContext = applicationContext;
mCurrentActivity = currentActivity;
mDefaultBackButtonImpl = defaultHardwareBackBtnHandler;
Expand All @@ -241,6 +245,7 @@ public static ReactInstanceManagerBuilder builder() {
mJSMainModulePath = jsMainModulePath;
mPackages = new ArrayList<>();
mUseDeveloperSupport = useDeveloperSupport;
mRequireActivity = requireActivity;
Systrace.beginSection(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ReactInstanceManager.initDevSupportManager");
mDevSupportManager =
Expand Down Expand Up @@ -558,16 +563,20 @@ public void onHostPause() {
* @param activity the activity being paused
*/
@ThreadConfined(UI)
public void onHostPause(Activity activity) {
Assertions.assertNotNull(mCurrentActivity);
Assertions.assertCondition(
activity == mCurrentActivity,
"Pausing an activity that is not the current activity, this is incorrect! "
+ "Current activity: "
+ mCurrentActivity.getClass().getSimpleName()
+ " "
+ "Paused activity: "
+ activity.getClass().getSimpleName());
public void onHostPause(@Nullable Activity activity) {
if (mRequireActivity) {
Assertions.assertCondition(mCurrentActivity != null);
}
if (mCurrentActivity != null) {
Assertions.assertCondition(
activity == mCurrentActivity,
"Pausing an activity that is not the current activity, this is incorrect! "
+ "Current activity: "
+ mCurrentActivity.getClass().getSimpleName()
+ " "
+ "Paused activity: "
+ activity.getClass().getSimpleName());
}
onHostPause();
}

Expand All @@ -583,7 +592,8 @@ public void onHostPause(Activity activity) {
* this instance of {@link ReactInstanceManager}.
*/
@ThreadConfined(UI)
public void onHostResume(Activity activity, DefaultHardwareBackBtnHandler defaultBackButtonImpl) {
public void onHostResume(
@Nullable Activity activity, DefaultHardwareBackBtnHandler defaultBackButtonImpl) {
UiThreadUtil.assertOnUiThread();

mDefaultBackButtonImpl = defaultBackButtonImpl;
Expand All @@ -592,7 +602,7 @@ public void onHostResume(Activity activity, DefaultHardwareBackBtnHandler defaul

/** Use this method when the activity resumes. */
@ThreadConfined(UI)
public void onHostResume(Activity activity) {
public void onHostResume(@Nullable Activity activity) {
UiThreadUtil.assertOnUiThread();

mCurrentActivity = activity;
Expand Down Expand Up @@ -631,8 +641,8 @@ public void onViewDetachedFromWindow(View v) {
// activity is attached to window, we can enable dev support immediately
mDevSupportManager.setDevSupportEnabled(true);
}
} else {
// there is no activity, we can enable dev support
} else if (!mRequireActivity) {
// there is no activity, but we can enable dev support
mDevSupportManager.setDevSupportEnabled(true);
}
}
Expand Down Expand Up @@ -666,7 +676,9 @@ public void onHostDestroy() {
* @param activity the activity being destroyed
*/
@ThreadConfined(UI)
public void onHostDestroy(Activity activity) {
public void onHostDestroy(@Nullable Activity activity) {
// In some cases, Activity may (correctly) be null.
// See mRequireActivity flag.
if (activity == mCurrentActivity) {
onHostDestroy();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class ReactInstanceManagerBuilder {
private @Nullable NotThreadSafeBridgeIdleDebugListener mBridgeIdleDebugListener;
private @Nullable Application mApplication;
private boolean mUseDeveloperSupport;
private boolean mRequireActivity;
private @Nullable LifecycleState mInitialLifecycleState;
private @Nullable UIImplementationProvider mUIImplementationProvider;
private @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
Expand Down Expand Up @@ -171,6 +172,16 @@ public ReactInstanceManagerBuilder setUseDeveloperSupport(boolean useDeveloperSu
return this;
}

/**
* When {@code false}, indicates that correct usage of React Native will NOT involve an Activity.
* For the vast majority of Android apps in the ecosystem, this will not need to change. Unless
* you really know what you're doing, you should probably not change this!
*/
public ReactInstanceManagerBuilder setRequireActivity(boolean requireActivity) {
mRequireActivity = requireActivity;
return this;
}

/**
* Sets the initial lifecycle state of the host. For example, if the host is already resumed at
* creation time, we wouldn't expect an onResume call until we get an onPause call.
Expand Down Expand Up @@ -283,6 +294,7 @@ public ReactInstanceManager build() {
mJSMainModulePath,
mPackages,
mUseDeveloperSupport,
mRequireActivity,
mBridgeIdleDebugListener,
Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"),
mUIImplementationProvider,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ protected ReactInstanceManager createReactInstanceManager() {
.setApplication(mApplication)
.setJSMainModulePath(getJSMainModuleName())
.setUseDeveloperSupport(getUseDeveloperSupport())
.setRequireActivity(getShouldRequireActivity())
.setRedBoxHandler(getRedBoxHandler())
.setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())
.setUIImplementationProvider(getUIImplementationProvider())
Expand Down Expand Up @@ -124,6 +125,11 @@ protected UIImplementationProvider getUIImplementationProvider() {
return null;
}

/** Returns whether or not to treat it as normal if Activity is null. */
public boolean getShouldRequireActivity() {
return true;
}

/**
* Returns the name of the main module. Determines the URL used to fetch the JS bundle from Metro.
* It is only used when dev support is enabled. This is the first file to be executed once the
Expand Down

0 comments on commit 4841e1b

Please sign in to comment.