Permalink
Browse files

Allow reactinstancemanager to set an initialization function

Reviewed By: javache

Differential Revision: D5227811

fbshipit-source-id: e7868481de2a8799af5d6a6bcad26369d054b35e
  • Loading branch information...
Kathy Gray authored and facebook-github-bot committed Aug 14, 2017
1 parent 6783694 commit 84e80eb78169f3e41e9bdad81b76387983379bdf
@@ -55,6 +55,7 @@
import com.facebook.react.bridge.ReactMarker;
import com.facebook.react.bridge.ReactMarkerConstants;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.bridge.NativeArray;
import com.facebook.react.bridge.queue.ReactQueueConfigurationSpec;
import com.facebook.react.common.LifecycleState;
import com.facebook.react.common.ReactConstants;
@@ -105,6 +106,8 @@
@ThreadSafe
public class ReactInstanceManager {
private static final String TAG = ReactInstanceManager.class.getSimpleName();
/**
* Listener interface for react instance events.
*/
@@ -127,6 +130,7 @@
private final @Nullable JSBundleLoader mBundleLoader; /* path to JS bundle on file system */
private final @Nullable String mJSMainModulePath; /* path to JS bundle root on packager server */
private final List<ReactPackage> mPackages;
private final List<CatalystInstanceImpl.PendingJSCall> mInitFunctions;
private final DevSupportManager mDevSupportManager;
private final boolean mUseDeveloperSupport;
private final @Nullable NotThreadSafeBridgeIdleDebugListener mBridgeIdleDebugListener;
@@ -232,6 +236,7 @@ public static ReactInstanceManagerBuilder builder() {
mBundleLoader = bundleLoader;
mJSMainModulePath = jsMainModulePath;
mPackages = new ArrayList<>();
mInitFunctions = new ArrayList<>();
mUseDeveloperSupport = useDeveloperSupport;
mDevSupportManager = DevSupportManagerFactory.create(
applicationContext,
@@ -351,11 +356,33 @@ public void registerAdditionalPackages(List<ReactPackage> packages) {
}
/**
* Recreate the react application and context. This should be called if configuration has
* changed or the developer has requested the app to be reloaded. It should only be called after
* an initial call to createReactContextInBackground.
* If the JavaScript bundle for this app requires initialization as part of bridge start up,
* register a function using its @param module and @param method and optional arguments.
*/
public void registerInitFunction(String module, String method, @Nullable NativeArray arguments) {
CatalystInstanceImpl.PendingJSCall init =
new CatalystInstanceImpl.PendingJSCall(module, method, arguments);
synchronized (this) {
mInitFunctions.add(init);
}
ReactContext context = getCurrentReactContext();
CatalystInstance catalystInstance = context == null ? null : context.getCatalystInstance();
if (catalystInstance == null) {
return;
} else {
// CatalystInstance is only visible after running jsBundle, so these will be put on the native
// JS queue
// TODO T20546472 remove cast when catalystInstance and InstanceImpl are renamed/merged
((CatalystInstanceImpl) catalystInstance).callFunction(init);
}
}
/**
* Recreate the react application and context. This should be called if configuration has changed
* or the developer has requested the app to be reloaded. It should only be called after an
* initial call to createReactContextInBackground.
*
* Called from UI thread.
* <p>Called from UI thread.
*/
@ThreadConfined(UI)
public void recreateReactContextInBackground() {
@@ -995,10 +1022,19 @@ private ReactApplicationContext createReactContext(
if (Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JSC_CALLS)) {
catalystInstance.setGlobalVariable("__RCTProfileIsProfiling", "true");
}
catalystInstance.runJSBundle();
reactContext.initializeWithInstance(catalystInstance);
// Transitions functions in the minitFunctions list to catalystInstance, to run after the bundle
// TODO T20546472
if (!mInitFunctions.isEmpty()) {
for (CatalystInstanceImpl.PendingJSCall function : mInitFunctions) {
((CatalystInstanceImpl) catalystInstance).callFunction(function);
}
}
ReactMarker.logMarker(ReactMarkerConstants.PRE_RUN_JS_BUNDLE_START);
catalystInstance.runJSBundle();
reactContext.initializeWithInstance(catalystInstance);
return reactContext;
}
@@ -43,20 +43,27 @@
private static final AtomicInteger sNextInstanceIdForTrace = new AtomicInteger(1);
private static class PendingJSCall {
public static class PendingJSCall {
public String mModule;
public String mMethod;
public NativeArray mArguments;
public @Nullable NativeArray mArguments;
public PendingJSCall(
String module,
String method,
NativeArray arguments) {
public PendingJSCall(String module, String method, @Nullable NativeArray arguments) {
mModule = module;
mMethod = method;
mArguments = arguments;
}
void call(CatalystInstanceImpl catalystInstance) {
NativeArray arguments = mArguments != null ? mArguments : new WritableNativeArray();
catalystInstance.jniCallJSFunction(mModule, mMethod, arguments);
}
public String toString() {
return mModule + "." + mMethod + "("
+ (mArguments == null ? "" : mArguments.toString()) + ")";
}
}
// Access from any thread
@@ -216,7 +223,6 @@ private native void initializeBridge(
public void runJSBundle() {
Log.d(ReactConstants.TAG, "CatalystInstanceImpl.runJSBundle()");
Assertions.assertCondition(!mJSBundleHasLoaded, "JS bundle was already loaded!");
// incrementPendingJSCalls();
mJSBundleLoader.loadScript(CatalystInstanceImpl.this);
@@ -227,8 +233,8 @@ public void runJSBundle() {
// gates will be queued on the JS thread behind the load.
mAcceptCalls = true;
for (PendingJSCall call : mJSCallsPendingInit) {
jniCallJSFunction(call.mModule, call.mMethod, call.mArguments);
for (PendingJSCall function : mJSCallsPendingInit) {
function.call(this);
}
mJSCallsPendingInit.clear();
mJSBundleHasLoaded = true;
@@ -260,22 +266,25 @@ public void callFunction(
final String module,
final String method,
final NativeArray arguments) {
callFunction(new PendingJSCall(module, method, arguments));
}
public void callFunction(PendingJSCall function) {
if (mDestroyed) {
final String call = module + "." + method + "(" + arguments.toString() + ")";
final String call = function.toString();
FLog.w(ReactConstants.TAG, "Calling JS function after bridge has been destroyed: " + call);
return;
}
if (!mAcceptCalls) {
// Most of the time the instance is initialized and we don't need to acquire the lock
synchronized (mJSCallsPendingInitLock) {
if (!mAcceptCalls) {
mJSCallsPendingInit.add(new PendingJSCall(module, method, arguments));
mJSCallsPendingInit.add(function);
return;
}
}
}
jniCallJSFunction(module, method, arguments);
function.call(this);
}
private native void jniCallJSCallback(int callbackID, NativeArray arguments);
@@ -186,14 +186,13 @@ public JSONObject toJSON() {
Matcher matcher = STACK_FRAME_PATTERN.matcher(stackTrace[i]);
if (!matcher.find()) {
throw new IllegalArgumentException(
"Unexpected stack frame format: " + stackTrace[i]);
"Unexpected stack frame format: " + stackTrace[i]);
}
result[i] = new StackFrameImpl(
matcher.group(2),
matcher.group(1) == null ? "(unknown)" : matcher.group(1),
Integer.parseInt(matcher.group(3)),
Integer.parseInt(matcher.group(4)));
matcher.group(2),
matcher.group(1) == null ? "(unknown)" : matcher.group(1),
Integer.parseInt(matcher.group(3)),
Integer.parseInt(matcher.group(4)));
}
}
return result;
@@ -88,6 +88,7 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
TypeElement typeElement = (TypeElement) reactModuleListElement;
ReactModuleList reactModuleList = typeElement.getAnnotation(ReactModuleList.class);
if (reactModuleList == null) {
continue;
}

0 comments on commit 84e80eb

Please sign in to comment.