react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
Andrew 00449b2654 Little docs correction
Summary:
Comma out
Closes https://github.com/facebook/react-native/pull/11491

Differential Revision: D4339939

Pulled By: lacker

fbshipit-source-id: 4945d9804e39809a10e92f42f60434fe69552782
2016-12-16 10:13:37 -08:00

429 lines
16 KiB
Java

/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.react;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.app.Application;
import android.content.Intent;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.common.annotations.VisibleForTesting;
import com.facebook.react.common.LifecycleState;
import com.facebook.react.cxxbridge.JSBundleLoader;
import com.facebook.react.devsupport.DevSupportManager;
import com.facebook.react.devsupport.RedBoxHandler;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.uimanager.UIImplementationProvider;
import com.facebook.react.uimanager.ViewManager;
/**
* This class is managing instances of {@link CatalystInstance}. It exposes a way to configure
* catalyst instance using {@link ReactPackage} and keeps track of the lifecycle of that
* instance. It also sets up connection between the instance and developers support functionality
* of the framework.
*
* An instance of this manager is required to start JS application in {@link ReactRootView} (see
* {@link ReactRootView#startReactApplication} for more info).
*
* 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 #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.
*/
public abstract class ReactInstanceManager {
/**
* Listener interface for react instance events.
*/
public interface ReactInstanceEventListener {
/**
* Called when the react context is initialized (all modules registered). Always called on the
* UI thread.
*/
void onReactContextInitialized(ReactContext context);
}
public abstract DevSupportManager getDevSupportManager();
public abstract MemoryPressureRouter getMemoryPressureRouter();
/**
* Trigger react context initialization asynchronously in a background async task. This enables
* applications to pre-load the application JS, and execute global code before
* {@link ReactRootView} is available and measured. This should only be called the first time the
* application is set up, which is enforced to keep developers from accidentally creating their
* application multiple times without realizing it.
*
* Called from UI thread.
*/
public abstract void createReactContextInBackground();
/**
* @return whether createReactContextInBackground has been called. Will return false after
* onDestroy until a new initial context has been created.
*/
public abstract boolean hasStartedCreatingInitialContext();
/**
* This method will give JS the opportunity to consume the back button event. If JS does not
* consume the event, mDefaultBackButtonImpl will be invoked at the end of the round trip to JS.
*/
public abstract void onBackPressed();
/**
* This method will give JS the opportunity to receive intents via Linking.
*/
public abstract void onNewIntent(Intent intent);
/**
* Call this from {@link Activity#onPause()}. This notifies any listening modules so they can do
* any necessary cleanup.
*
* @deprecated Use {@link #onHostPause(Activity)} instead.
*/
@Deprecated
public abstract void onHostPause();
/**
* Call this from {@link Activity#onPause()}. This notifies any listening modules so they can do
* any necessary cleanup. The passed Activity is the current Activity being paused. This will
* always be the foreground activity that would be returned by
* {@link ReactContext#getCurrentActivity()}.
*
* @param activity the activity being paused
*/
public abstract void onHostPause(Activity activity);
/**
* 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 #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 onHostResume(
Activity activity,
DefaultHardwareBackBtnHandler defaultBackButtonImpl);
/**
* Call this from {@link Activity#onDestroy()}. This notifies any listening modules so they can do
* any necessary cleanup.
*
* @deprecated use {@link #onHostDestroy(Activity)} instead
*/
@Deprecated
public abstract void onHostDestroy();
/**
* Call this from {@link Activity#onDestroy()}. This notifies any listening modules so they can do
* any necessary cleanup. If the activity being destroyed is not the current activity, no modules
* are notified.
*
* @param activity the activity being destroyed
*/
public abstract void onHostDestroy(Activity activity);
public abstract void onActivityResult(
Activity activity,
int requestCode,
int resultCode,
Intent data);
public abstract void showDevOptionsDialog();
/**
* Get the URL where the last bundle was loaded from.
*/
public abstract String getSourceUrl();
/**
* The JS Bundle file that this Instance Manager was constructed with.
*/
public abstract @Nullable String getJSBundleFile();
/**
* Attach given {@param rootView} to a catalyst instance manager and start JS application using
* JS module provided by {@link ReactRootView#getJSModuleName}. If the react context is currently
* being (re)-created, or if react context has not been created yet, the JS application associated
* with the provided root view will be started asynchronously, i.e this method won't block.
* This view will then be tracked by this manager and in case of catalyst instance restart it will
* be re-attached.
*/
public abstract void attachMeasuredRootView(ReactRootView rootView);
/**
* Detach given {@param rootView} from current catalyst instance. It's safe to call this method
* multiple times on the same {@param rootView} - in that case view will be detached with the
* first call.
*/
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
*/
public abstract List<ViewManager> createAllViewManagers(
ReactApplicationContext catalystApplicationContext);
/**
* Add a listener to be notified of react instance events.
*/
public abstract void addReactInstanceEventListener(ReactInstanceEventListener listener);
/**
* Remove a listener previously added with {@link #addReactInstanceEventListener}.
*/
public abstract void removeReactInstanceEventListener(ReactInstanceEventListener listener);
@VisibleForTesting
public abstract @Nullable ReactContext getCurrentReactContext();
public abstract LifecycleState getLifecycleState();
/**
* Creates a builder that is capable of creating an instance of {@link ReactInstanceManagerImpl}.
*/
public static Builder builder() {
return new Builder();
}
/**
* Builder class for {@link ReactInstanceManagerImpl}
*/
public static class Builder {
protected final List<ReactPackage> mPackages = new ArrayList<>();
protected @Nullable String mJSBundleAssetUrl;
protected @Nullable JSBundleLoader mJSBundleLoader;
protected @Nullable String mJSMainModuleName;
protected @Nullable NotThreadSafeBridgeIdleDebugListener mBridgeIdleDebugListener;
protected @Nullable Application mApplication;
protected boolean mUseDeveloperSupport;
protected @Nullable LifecycleState mInitialLifecycleState;
protected @Nullable UIImplementationProvider mUIImplementationProvider;
protected @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
protected JSCConfig mJSCConfig = JSCConfig.EMPTY;
protected @Nullable Activity mCurrentActivity;
protected @Nullable DefaultHardwareBackBtnHandler mDefaultHardwareBackBtnHandler;
protected @Nullable RedBoxHandler mRedBoxHandler;
protected boolean mLazyNativeModulesEnabled;
protected boolean mLazyViewManagersEnabled;
protected Builder() {
}
/**
* Sets a provider of {@link UIImplementation}.
* Uses default provider if null is passed.
*/
public Builder setUIImplementationProvider(
@Nullable UIImplementationProvider uiImplementationProvider) {
mUIImplementationProvider = uiImplementationProvider;
return this;
}
/**
* Name of the JS bundle file to be loaded from application's raw assets.
* Example: {@code "index.android.js"}
*/
public Builder setBundleAssetName(String bundleAssetName) {
mJSBundleAssetUrl = (bundleAssetName == null ? null : "assets://" + bundleAssetName);
mJSBundleLoader = null;
return this;
}
/**
* Path to the JS bundle file to be loaded from the file system.
*
* Example: {@code "assets://index.android.js" or "/sdcard/main.jsbundle"}
*/
public Builder setJSBundleFile(String jsBundleFile) {
if (jsBundleFile.startsWith("assets://")) {
mJSBundleAssetUrl = jsBundleFile;
mJSBundleLoader = null;
return this;
}
return setJSBundleLoader(JSBundleLoader.createFileLoader(jsBundleFile));
}
/**
* Bundle loader to use when setting up JS environment. This supersedes
* prior invcations of {@link setJSBundleFile} and {@link setBundleAssetName}.
*
* Example: {@code JSBundleLoader.createFileLoader(application, bundleFile)}
*/
public Builder setJSBundleLoader(JSBundleLoader jsBundleLoader) {
mJSBundleLoader = jsBundleLoader;
mJSBundleAssetUrl = null;
return this;
}
/**
* Path to your app's main module on the packager server. This is used when
* reloading JS during development. All paths are relative to the root folder
* the packager is serving files from.
* Examples:
* {@code "index.android"} or
* {@code "subdirectory/index.android"}
*/
public Builder setJSMainModuleName(String jsMainModuleName) {
mJSMainModuleName = jsMainModuleName;
return this;
}
public Builder addPackage(ReactPackage reactPackage) {
mPackages.add(reactPackage);
return this;
}
public Builder setBridgeIdleDebugListener(
NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener) {
mBridgeIdleDebugListener = bridgeIdleDebugListener;
return this;
}
/**
* Required. This must be your {@code Application} instance.
*/
public Builder setApplication(Application application) {
mApplication = application;
return this;
}
public Builder setCurrentActivity(Activity activity) {
mCurrentActivity = activity;
return this;
}
public Builder setDefaultHardwareBackBtnHandler(
DefaultHardwareBackBtnHandler defaultHardwareBackBtnHandler) {
mDefaultHardwareBackBtnHandler = defaultHardwareBackBtnHandler;
return this;
}
/**
* When {@code true}, developer options such as JS reloading and debugging are enabled.
* Note you still have to call {@link #showDevOptionsDialog} to show the dev menu,
* e.g. when the device Menu button is pressed.
*/
public Builder setUseDeveloperSupport(boolean useDeveloperSupport) {
mUseDeveloperSupport = useDeveloperSupport;
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.
*/
public Builder setInitialLifecycleState(LifecycleState initialLifecycleState) {
mInitialLifecycleState = initialLifecycleState;
return this;
}
/**
* Set the exception handler for all native module calls. If not set, the default
* {@link DevSupportManager} will be used, which shows a redbox in dev mode and rethrows
* (crashes the app) in prod mode.
*/
public Builder setNativeModuleCallExceptionHandler(NativeModuleCallExceptionHandler handler) {
mNativeModuleCallExceptionHandler = handler;
return this;
}
public Builder setJSCConfig(JSCConfig jscConfig) {
mJSCConfig = jscConfig;
return this;
}
public Builder setRedBoxHandler(@Nullable RedBoxHandler redBoxHandler) {
mRedBoxHandler = redBoxHandler;
return this;
}
public Builder setLazyNativeModulesEnabled(boolean lazyNativeModulesEnabled) {
mLazyNativeModulesEnabled = lazyNativeModulesEnabled;
return this;
}
public Builder setLazyViewManagersEnabled(boolean lazyViewManagersEnabled) {
mLazyViewManagersEnabled = lazyViewManagersEnabled;
return this;
}
/**
* Instantiates a new {@link ReactInstanceManagerImpl}.
* Before calling {@code build}, the following must be called:
* <ul>
* <li> {@link #setApplication}
* <li> {@link #setCurrentActivity} if the activity has already resumed
* <li> {@link #setDefaultHardwareBackBtnHandler} if the activity has already resumed
* <li> {@link #setJSBundleFile} or {@link #setJSMainModuleName}
* </ul>
*/
public ReactInstanceManager build() {
Assertions.assertNotNull(
mApplication,
"Application property has not been set with this builder");
Assertions.assertCondition(
mUseDeveloperSupport || mJSBundleAssetUrl != null || mJSBundleLoader != null,
"JS Bundle File or Asset URL has to be provided when dev support is disabled");
Assertions.assertCondition(
mJSMainModuleName != null || mJSBundleAssetUrl != null || mJSBundleLoader != null,
"Either MainModuleName or JS Bundle File needs to be provided");
if (mUIImplementationProvider == null) {
// create default UIImplementationProvider if the provided one is null.
mUIImplementationProvider = new UIImplementationProvider();
}
return new XReactInstanceManagerImpl(
mApplication,
mCurrentActivity,
mDefaultHardwareBackBtnHandler,
(mJSBundleLoader == null && mJSBundleAssetUrl != null) ?
JSBundleLoader.createAssetLoader(mApplication, mJSBundleAssetUrl) : mJSBundleLoader,
mJSMainModuleName,
mPackages,
mUseDeveloperSupport,
mBridgeIdleDebugListener,
Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"),
mUIImplementationProvider,
mNativeModuleCallExceptionHandler,
mJSCConfig,
mRedBoxHandler,
mLazyNativeModulesEnabled,
mLazyViewManagersEnabled);
}
}
}