private void setupReactContext(ReactApplicationContext reactContext) { Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "setupReactContext"); UiThreadUtil.assertOnUiThread(); Assertions.assertCondition(mCurrentReactContext == null); mCurrentReactContext = Assertions.assertNotNull(reactContext); CatalystInstance catalystInstance = Assertions.assertNotNull(reactContext.getCatalystInstance()); catalystInstance.initialize(); mDevSupportManager.onNewReactContextCreated(reactContext); mMemoryPressureRouter.addMemoryPressureListener(catalystInstance); moveReactContextToCurrentLifecycleState(); for (ReactRootView rootView : mAttachedRootViews) { attachMeasuredRootViewToInstance(rootView, catalystInstance); } ReactInstanceEventListener[] listeners = new ReactInstanceEventListener[mReactInstanceEventListeners.size()]; listeners = mReactInstanceEventListeners.toArray(listeners); for (ReactInstanceEventListener listener : listeners) { listener.onReactContextInitialized(reactContext); } Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE); }
@Override public void destroy() { UiThreadUtil.assertOnUiThread(); if (mUseDeveloperSupport) { mDevSupportManager.setDevSupportEnabled(false); } moveToBeforeCreateLifecycleState(); if (mReactContextInitAsyncTask != null) { mReactContextInitAsyncTask.cancel(true); } mMemoryPressureRouter.destroy(mApplicationContext); if (mCurrentReactContext != null) { mCurrentReactContext.destroy(); mCurrentReactContext = null; mHasStartedCreatingInitialContext = false; } mCurrentActivity = null; ResourceDrawableIdHelper.getInstance().clear(); }
/** * 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. */ @Override public void detachRootView(ReactRootView rootView) { UiThreadUtil.assertOnUiThread(); if (mAttachedRootViews.remove(rootView)) { if (mCurrentReactContext != null && mCurrentReactContext.hasActiveCatalystInstance()) { detachViewFromInstance(rootView, mCurrentReactContext.getCatalystInstance()); } } }
/** * 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. */ @Override public void attachMeasuredRootView(ReactRootView rootView) { UiThreadUtil.assertOnUiThread(); mAttachedRootViews.add(rootView); // If react context is being created in the background, JS application will be started // automatically when creation completes, as root view is part of the attached root view list. if (mReactContextInitAsyncTask == null && mCurrentReactContext != null) { attachMeasuredRootViewToInstance(rootView, mCurrentReactContext.getCatalystInstance()); } }
@Override public void onHostDestroy() { UiThreadUtil.assertOnUiThread(); if (mUseDeveloperSupport) { mDevSupportManager.setDevSupportEnabled(false); } moveToBeforeCreateLifecycleState(); mCurrentActivity = null; }
private void tearDownReactContext(ReactContext reactContext) { UiThreadUtil.assertOnUiThread(); if (mLifecycleState == LifecycleState.RESUMED) { reactContext.onHostPause(); } for (ReactRootView rootView : mAttachedRootViews) { detachViewFromInstance(rootView, reactContext.getCatalystInstance()); } reactContext.destroy(); mDevSupportManager.onReactInstanceDestroyed(reactContext); mMemoryPressureRouter.removeMemoryPressureListener(reactContext.getCatalystInstance()); }
/** * Use this method when the activity resumes to enable invoking the back button directly from JS. * * <p>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 * XReactInstanceManagerImpl}, 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 XReactInstanceManagerImpl}. */ @Override public void onHostResume(Activity activity, DefaultHardwareBackBtnHandler defaultBackButtonImpl) { UiThreadUtil.assertOnUiThread(); mDefaultBackButtonImpl = defaultBackButtonImpl; if (mUseDeveloperSupport) { mDevSupportManager.setDevSupportEnabled(true); } mCurrentActivity = activity; moveToResumedLifecycleState(false); }
@Override public void onHostPause() { UiThreadUtil.assertOnUiThread(); mDefaultBackButtonImpl = null; if (mUseDeveloperSupport) { mDevSupportManager.setDevSupportEnabled(false); } moveToBeforeResumeLifecycleState(); mCurrentActivity = null; }
/** * 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. */ @Override public void onBackPressed() { UiThreadUtil.assertOnUiThread(); ReactContext reactContext = mCurrentReactContext; if (mCurrentReactContext == null) { // Invoke without round trip to JS. FLog.w(ReactConstants.TAG, "Instance detached from instance manager"); invokeDefaultOnBackPressed(); } else { DeviceEventManagerModule deviceEventManagerModule = Assertions.assertNotNull(reactContext).getNativeModule(DeviceEventManagerModule.class); deviceEventManagerModule.emitHardwareBackPressed(); } }
private void recreateReactContextInBackground( JavaScriptExecutor.Factory jsExecutorFactory, JSBundleLoader jsBundleLoader) { UiThreadUtil.assertOnUiThread(); ReactContextInitParams initParams = new ReactContextInitParams(jsExecutorFactory, jsBundleLoader); if (mReactContextInitAsyncTask == null) { // No background task to create react context is currently running, create and execute one. mReactContextInitAsyncTask = new ReactContextInitAsyncTask(); mReactContextInitAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, initParams); } else { // Background task is currently running, queue up most recent init params to recreate context // once task completes. mPendingReactContextInitParams = initParams; } }
private void attachMeasuredRootViewToInstance( ReactRootView rootView, CatalystInstance catalystInstance) { Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "attachMeasuredRootViewToInstance"); UiThreadUtil.assertOnUiThread(); // Reset view content as it's going to be populated by the application content from JS rootView.removeAllViews(); rootView.setId(View.NO_ID); UIManagerModule uiManagerModule = catalystInstance.getNativeModule(UIManagerModule.class); int rootTag = uiManagerModule.addMeasuredRootView(rootView); @Nullable Bundle launchOptions = rootView.getLaunchOptions(); WritableMap initialProps = Arguments.makeNativeMap(launchOptions); String jsAppModuleName = rootView.getJSModuleName(); WritableNativeMap appParams = new WritableNativeMap(); appParams.putDouble("rootTag", rootTag); appParams.putMap("initialProps", initialProps); catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams); Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE); }
private void recreateReactContextInBackgroundInner() { UiThreadUtil.assertOnUiThread(); if (mUseDeveloperSupport && mJSMainModuleName != null) { final DeveloperSettings devSettings = mDevSupportManager.getDevSettings(); // If remote JS debugging is enabled, load from dev server. if (mDevSupportManager.hasUpToDateJSBundleInCache() && !devSettings.isRemoteJSDebugEnabled()) { // If there is a up-to-date bundle downloaded from server, // with remote JS debugging disabled, always use that. onJSBundleLoadedFromServer(); } else if (mBundleLoader == null) { mDevSupportManager.handleReloadJS(); } else { mDevSupportManager.isPackagerRunning( new DevServerHelper.PackagerStatusCallback() { @Override public void onPackagerStatusFetched(final boolean packagerIsRunning) { UiThreadUtil.runOnUiThread( new Runnable() { @Override public void run() { if (packagerIsRunning) { mDevSupportManager.handleReloadJS(); } else { // If dev server is down, disable the remote JS debugging. devSettings.setRemoteJSDebugEnabled(false); recreateReactContextInBackgroundFromBundleLoader(); } } }); } }); } return; } recreateReactContextInBackgroundFromBundleLoader(); }
private void detachViewFromInstance(ReactRootView rootView, CatalystInstance catalystInstance) { UiThreadUtil.assertOnUiThread(); catalystInstance .getJSModule(AppRegistry.class) .unmountApplicationComponentAtRootTag(rootView.getId()); }
@Override public void showDevOptionsDialog() { UiThreadUtil.assertOnUiThread(); mDevSupportManager.showDevOptionsDialog(); }
private void invokeDefaultOnBackPressed() { UiThreadUtil.assertOnUiThread(); if (mDefaultBackButtonImpl != null) { mDefaultBackButtonImpl.invokeDefaultOnBackPressed(); } }