diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java index d8ec7ae929..fd3946eeb7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java @@ -90,6 +90,13 @@ public class NativeViewHierarchyOptimizer { } } + /** + * Handles native children cleanup when css node is removed from hierarchy + */ + public static void handleRemoveNode(ReactShadowNode node) { + node.removeAllNativeChildren(); + } + /** * Handles an updateView call. If a view transitions from being layout-only to not (or vice-versa) * this could result in some number of additional createView and manageChildren calls. If the diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java index d9ee6d8b58..73134194fb 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java @@ -137,20 +137,22 @@ public class ReactShadowNode extends CSSNode { } public void removeAllChildren() { + int decrease = 0; for (int i = getChildCount() - 1; i >= 0; i--) { - super.removeChildAt(i); + ReactShadowNode removed = (ReactShadowNode) super.removeChildAt(i); + decrease += removed.mIsLayoutOnly ? removed.mTotalNativeChildren : 1; } markUpdated(); - updateNativeChildrenCountInParent(-mTotalNativeChildren); - mTotalNativeChildren = 0; + mTotalNativeChildren -= decrease; + updateNativeChildrenCountInParent(-decrease); } private void updateNativeChildrenCountInParent(int delta) { if (mIsLayoutOnly) { ReactShadowNode parent = getParent(); while (parent != null) { - parent.mTotalNativeChildren -= delta; + parent.mTotalNativeChildren += delta; if (!parent.mIsLayoutOnly) { break; } @@ -289,6 +291,15 @@ public class ReactShadowNode extends CSSNode { return removed; } + public void removeAllNativeChildren() { + if (mNativeChildren != null) { + for (int i = mNativeChildren.size() - 1; i >= 0; i--) { + mNativeChildren.get(i).mNativeParent = null; + } + mNativeChildren.clear(); + } + } + public int getNativeChildCount() { return mNativeChildren == null ? 0 : mNativeChildren.size(); } 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 12cae17127..bb68616be0 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java @@ -399,17 +399,17 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements } for (int i = 0; i < tagsToDelete.length; i++) { - removeCSSNode(tagsToDelete[i]); + removeShadowNode(mShadowNodeRegistry.getNode(tagsToDelete[i])); } } - private void removeCSSNode(int tag) { - ReactShadowNode node = mShadowNodeRegistry.getNode(tag); - mShadowNodeRegistry.removeNode(tag); - for (int i = node.getChildCount() - 1; i >= 0; i--) { - removeCSSNode(node.getChildAt(i).getReactTag()); + private void removeShadowNode(ReactShadowNode nodeToRemove) { + mNativeViewHierarchyOptimizer.handleRemoveNode(nodeToRemove); + mShadowNodeRegistry.removeNode(nodeToRemove.getReactTag()); + for (int i = nodeToRemove.getChildCount() - 1; i >= 0; i--) { + removeShadowNode(nodeToRemove.getChildAt(i)); } - node.removeAllChildren(); + nodeToRemove.removeAllChildren(); } /**