9292import  com .facebook .react .modules .core .DeviceEventManagerModule ;
9393import  com .facebook .react .modules .core .ReactChoreographer ;
9494import  com .facebook .react .modules .debug .interfaces .DeveloperSettings ;
95- import  com .facebook .react .modules .fabric .ReactFabric ;
9695import  com .facebook .react .packagerconnection .RequestHandler ;
9796import  com .facebook .react .surface .ReactStage ;
9897import  com .facebook .react .turbomodule .core .TurboModuleManager ;
102101import  com .facebook .react .uimanager .ReactRoot ;
103102import  com .facebook .react .uimanager .UIManagerHelper ;
104103import  com .facebook .react .uimanager .ViewManager ;
104+ import  com .facebook .react .uimanager .common .UIManagerType ;
105105import  com .facebook .react .views .imagehelper .ResourceDrawableIdHelper ;
106106import  com .facebook .soloader .SoLoader ;
107107import  com .facebook .systrace .Systrace ;
@@ -855,7 +855,10 @@ private void clearReactRoot(ReactRoot reactRoot) {
855855   * with the provided reactRoot reactRoot will be started asynchronously, i.e this method won't 
856856   * block. This reactRoot will then be tracked by this manager and in case of catalyst instance 
857857   * restart it will be re-attached. 
858+    * 
859+    * @deprecated This method should be internal to ReactRootView and ReactInstanceManager 
858860   */ 
861+   @ Deprecated 
859862  @ ThreadConfined (UI )
860863  public  void  attachRootView (ReactRoot  reactRoot ) {
861864    UiThreadUtil .assertOnUiThread ();
@@ -865,35 +868,37 @@ public void attachRootView(ReactRoot reactRoot) {
865868    // Ideally reactRoot should be initialized with id == NO_ID 
866869    if  (mAttachedReactRoots .add (reactRoot )) {
867870      clearReactRoot (reactRoot );
871+     } else  {
872+       FLog .e (ReactConstants .TAG , "ReactRoot was attached multiple times" );
868873    }
869874
870875    // If react context is being created in the background, JS application will be started 
871876    // automatically when creation completes, as reactRoot is part of the attached 
872877    // reactRoot list. 
873878    ReactContext  currentContext  = getCurrentReactContext ();
874879    if  (mCreateReactContextThread  == null  && currentContext  != null ) {
875-       if  (reactRoot .getState ().compareAndSet (ReactRoot .STATE_STOPPED , ReactRoot .STATE_STARTED )) {
876-         attachRootViewToInstance (reactRoot );
877-       }
880+       attachRootViewToInstance (reactRoot );
878881    }
879882  }
880883
881884  /** 
882885   * Detach given {@param reactRoot} from current catalyst instance. It's safe to call this method 
883886   * multiple times on the same {@param reactRoot} - in that case view will be detached with the 
884887   * first call. 
888+    * 
889+    * @deprecated This method should be internal to ReactRootView and ReactInstanceManager 
885890   */ 
891+   @ Deprecated 
886892  @ ThreadConfined (UI )
887893  public  void  detachRootView (ReactRoot  reactRoot ) {
888894    UiThreadUtil .assertOnUiThread ();
889-     synchronized  (mAttachedReactRoots ) {
890-       if  (mAttachedReactRoots .contains (reactRoot )) {
891-         ReactContext  currentContext  = getCurrentReactContext ();
892-         mAttachedReactRoots .remove (reactRoot );
893-         if  (currentContext  != null  && currentContext .hasActiveReactInstance ()) {
894-           detachViewFromInstance (reactRoot , currentContext .getCatalystInstance ());
895-         }
896-       }
895+     if  (!mAttachedReactRoots .remove (reactRoot )) {
896+       return ;
897+     }
898+ 
899+     ReactContext  reactContext  = mCurrentReactContext ;
900+     if  (reactContext  != null  && reactContext .hasActiveReactInstance ()) {
901+       detachRootViewFromInstance (reactRoot , reactContext );
897902    }
898903  }
899904
@@ -1150,9 +1155,7 @@ private void setupReactContext(final ReactApplicationContext reactContext) {
11501155
11511156      ReactMarker .logMarker (ATTACH_MEASURED_ROOT_VIEWS_START );
11521157      for  (ReactRoot  reactRoot  : mAttachedReactRoots ) {
1153-         if  (reactRoot .getState ().compareAndSet (ReactRoot .STATE_STOPPED , ReactRoot .STATE_STARTED )) {
1154-           attachRootViewToInstance (reactRoot );
1155-         }
1158+         attachRootViewToInstance (reactRoot );
11561159      }
11571160      ReactMarker .logMarker (ATTACH_MEASURED_ROOT_VIEWS_END );
11581161    }
@@ -1194,6 +1197,11 @@ private void setupReactContext(final ReactApplicationContext reactContext) {
11941197
11951198  private  void  attachRootViewToInstance (final  ReactRoot  reactRoot ) {
11961199    FLog .d (ReactConstants .TAG , "ReactInstanceManager.attachRootViewToInstance()" );
1200+     if  (!reactRoot .getState ().compareAndSet (ReactRoot .STATE_STOPPED , ReactRoot .STATE_STARTED )) {
1201+       // Already started 
1202+       return ;
1203+     }
1204+ 
11971205    Systrace .beginSection (TRACE_TAG_REACT_JAVA_BRIDGE , "attachRootViewToInstance" );
11981206
11991207    @ Nullable 
@@ -1210,7 +1218,6 @@ private void attachRootViewToInstance(final ReactRoot reactRoot) {
12101218    @ Nullable  Bundle  initialProperties  = reactRoot .getAppProperties ();
12111219
12121220    final  int  rootTag ;
1213- 
12141221    if  (reactRoot .getUIManagerType () == FABRIC ) {
12151222      rootTag  =
12161223          uiManager .startSurface (
@@ -1245,18 +1252,48 @@ private void attachRootViewToInstance(final ReactRoot reactRoot) {
12451252    Systrace .endSection (TRACE_TAG_REACT_JAVA_BRIDGE );
12461253  }
12471254
1248-   private  void  detachViewFromInstance (ReactRoot  reactRoot , CatalystInstance   catalystInstance ) {
1249-     FLog .d (ReactConstants .TAG , "ReactInstanceManager.detachViewFromInstance ()" );
1255+   private  void  detachRootViewFromInstance (ReactRoot  reactRoot , ReactContext   reactContext ) {
1256+     FLog .d (ReactConstants .TAG , "ReactInstanceManager.detachRootViewFromInstance ()" );
12501257    UiThreadUtil .assertOnUiThread ();
1251-     if  (reactRoot .getUIManagerType () == FABRIC ) {
1252-       catalystInstance 
1253-           .getJSModule (ReactFabric .class )
1254-           .unmountComponentAtNode (reactRoot .getRootViewTag ());
1258+ 
1259+     if  (!reactRoot .getState ().compareAndSet (ReactRoot .STATE_STARTED , ReactRoot .STATE_STOPPED )) {
1260+       // ReactRoot was already stopped 
1261+       return ;
1262+     }
1263+ 
1264+     @ UIManagerType  int  uiManagerType  = reactRoot .getUIManagerType ();
1265+     if  (uiManagerType  == UIManagerType .FABRIC ) {
1266+       // Stop surface in Fabric. 
1267+       // Calling FabricUIManager.stopSurface causes the C++ Binding.stopSurface 
1268+       // to be called synchronously over the JNI, which causes an empty tree 
1269+       // to be committed via the Scheduler, which will cause mounting instructions 
1270+       // to be queued up and synchronously executed to delete and remove 
1271+       // all the views in the hierarchy. 
1272+       final  int  surfaceId  = reactRoot .getRootViewTag ();
1273+       if  (surfaceId  != View .NO_ID ) {
1274+         UIManager  uiManager  = UIManagerHelper .getUIManager (reactContext , uiManagerType );
1275+         if  (uiManager  != null ) {
1276+           uiManager .stopSurface (surfaceId );
1277+         } else  {
1278+           FLog .w (ReactConstants .TAG , "Failed to stop surface, UIManager has already gone away" );
1279+           reactRoot .getRootViewGroup ().removeAllViews ();
1280+         }
1281+       } else  {
1282+         ReactSoftExceptionLogger .logSoftException (
1283+             TAG ,
1284+             new  RuntimeException (
1285+                 "detachRootViewFromInstance called with ReactRootView with invalid id" ));
1286+         reactRoot .getRootViewGroup ().removeAllViews ();
1287+       }
12551288    } else  {
1256-       catalystInstance 
1289+       reactContext 
1290+           .getCatalystInstance ()
12571291          .getJSModule (AppRegistry .class )
12581292          .unmountApplicationComponentAtRootTag (reactRoot .getRootViewTag ());
12591293    }
1294+ 
1295+     // The view is no longer attached, so mark it as such by resetting its ID. 
1296+     reactRoot .getRootViewGroup ().setId (View .NO_ID );
12601297  }
12611298
12621299  @ ThreadConfined (UI )
@@ -1269,7 +1306,7 @@ private void tearDownReactContext(ReactContext reactContext) {
12691306
12701307    synchronized  (mAttachedReactRoots ) {
12711308      for  (ReactRoot  reactRoot  : mAttachedReactRoots ) {
1272-         clearReactRoot (reactRoot );
1309+         detachRootViewFromInstance (reactRoot ,  reactContext );
12731310      }
12741311    }
12751312
0 commit comments