diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java index f152a30c432..2aee3b7b493 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java @@ -431,6 +431,23 @@ public class ReactRootView extends FrameLayout implements RootView, ReactRoot { @ThreadConfined(UI) public void unmountReactApplication() { UiThreadUtil.assertOnUiThread(); + // Stop surface in Fabric. + // Calling FabricUIManager.stopSurface causes the C++ Binding.stopSurface + // to be called synchronously over the JNI, which causes an empty tree + // to be committed via the Scheduler, which will cause mounting instructions + // to be queued up and synchronously executed to delete and remove + // all the views in the hierarchy. + if (mReactInstanceManager != null) { + final ReactContext reactApplicationContext = mReactInstanceManager.getCurrentReactContext(); + if (reactApplicationContext != null && getUIManagerType() == FABRIC) { + @Nullable + UIManager uiManager = + UIManagerHelper.getUIManager(reactApplicationContext, getUIManagerType()); + if (uiManager != null) { + uiManager.stopSurface(this.getId()); + } + } + } if (mReactInstanceManager != null && mIsAttachedToInstance) { mReactInstanceManager.detachRootView(this); diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManager.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManager.java index 4edebdcf00e..d6f6cd97365 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManager.java @@ -32,6 +32,13 @@ public interface UIManager extends JSIModule, PerformanceCounter { int widthMeasureSpec, int heightMeasureSpec); + /** + * Stop a surface from running in JS and clears up native memory usage. Assumes that the native + * View hierarchy has already been cleaned up. Fabric-only. + */ + @AnyThread + void stopSurface(final int surfaceId); + /** * Updates the layout specs of the RootShadowNode based on the Measure specs received by * parameters. diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index 4c863b70209..5ae1f6b9b2e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -242,6 +242,7 @@ public class FabricUIManager implements UIManager, LifecycleEventListener { @AnyThread @ThreadConfined(ANY) + @Override public void stopSurface(int surfaceID) { mBinding.stopSurface(surfaceID); mReactContextForRootTag.remove(surfaceID); diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java index 1f51e272ac9..823b1ad1395 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java @@ -437,6 +437,11 @@ public class UIManagerModule extends ReactContextBaseJavaModule throw new UnsupportedOperationException(); } + @Override + public void stopSurface(final int surfaceId) { + throw new UnsupportedOperationException(); + } + /** Unregisters a new root view. */ @ReactMethod public void removeRootView(int rootViewTag) {