Skip to content

Commit e1b3bbd

Browse files
Adam ComellaFacebook Github Bot 0
authored andcommitted
Android: Refactor HierarchyOptimizer in preparation of inline view support
Summary: This PR was split from commits originally in #8619. /cc dmmiller These refactorings to the HierarchyOptimizer are in preparation for implementing support for inline views in #8619. **Refactoring 1: Collapse add*LayoutOnlyNodeToLayoutOnlyNode** addLayoutOnlyNodeToLayoutOnlyNode and addNonLayoutOnlyNodeToLayoutOnlyNode had nearly identical implementations. They both walk thru the ancestors looking for a nonlayout-only node and adjusting the passed in index at each step. This introduces a new function, walkUpUntilNonLayoutOnly, which takes care of that responsibility. This simplifies addNodeToNode because it can now consider the type of the parent and the type of the child independently. **Refactoring 2: Extract addGrandchildren** Pull out addLayoutOnlyNode's logic into a helper called addGrandchildren. We will need to call this method in another place later. **Test plan (required)** This change was tested with UIExplorer and a small test app and it's being used in my team's app. Closes #8908 Differential Revision: D3592783 Pulled By: dmmiller fbshipit-source-id: a513e8d381e71112ce6348bbee7d4a7c62c33619
1 parent 0587c85 commit e1b3bbd

File tree

1 file changed

+68
-74
lines changed

1 file changed

+68
-74
lines changed

ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java

Lines changed: 68 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,16 @@
5252
*/
5353
public class NativeViewHierarchyOptimizer {
5454

55+
private static class NodeIndexPair {
56+
public final ReactShadowNode node;
57+
public final int index;
58+
59+
NodeIndexPair(ReactShadowNode node, int index) {
60+
this.node = node;
61+
this.index = index;
62+
}
63+
}
64+
5565
private static final boolean ENABLED = true;
5666

5767
private final UIViewOperationQueue mUIViewOperationQueue;
@@ -221,21 +231,39 @@ public void onBatchComplete() {
221231
mTagsWithLayoutVisited.clear();
222232
}
223233

234+
private NodeIndexPair walkUpUntilNonLayoutOnly(
235+
ReactShadowNode node,
236+
int indexInNativeChildren) {
237+
while (node.isLayoutOnly()) {
238+
ReactShadowNode parent = node.getParent();
239+
if (parent == null) {
240+
return null;
241+
}
242+
243+
indexInNativeChildren = indexInNativeChildren + parent.getNativeOffsetForChild(node);
244+
node = parent;
245+
}
246+
247+
return new NodeIndexPair(node, indexInNativeChildren);
248+
}
249+
224250
private void addNodeToNode(ReactShadowNode parent, ReactShadowNode child, int index) {
225251
int indexInNativeChildren = parent.getNativeOffsetForChild(parent.getChildAt(index));
226-
boolean parentIsLayoutOnly = parent.isLayoutOnly();
227-
boolean childIsLayoutOnly = child.isLayoutOnly();
228-
229-
// Switch on the four cases of:
230-
// add (layout-only|not layout-only) to (layout-only|not layout-only)
231-
if (!parentIsLayoutOnly && !childIsLayoutOnly) {
232-
addNonLayoutNodeToNonLayoutNode(parent, child, indexInNativeChildren);
233-
} else if (!childIsLayoutOnly) {
234-
addNonLayoutOnlyNodeToLayoutOnlyNode(parent, child, indexInNativeChildren);
235-
} else if (!parentIsLayoutOnly) {
236-
addLayoutOnlyNodeToNonLayoutOnlyNode(parent, child, indexInNativeChildren);
252+
if (parent.isLayoutOnly()) {
253+
NodeIndexPair result = walkUpUntilNonLayoutOnly(parent, indexInNativeChildren);
254+
if (result == null) {
255+
// If the parent hasn't been attached to its native parent yet, don't issue commands to the
256+
// native hierarchy. We'll do that when the parent node actually gets attached somewhere.
257+
return;
258+
}
259+
parent = result.node;
260+
indexInNativeChildren = result.index;
261+
}
262+
263+
if (!child.isLayoutOnly()) {
264+
addNonLayoutNode(parent, child, indexInNativeChildren);
237265
} else {
238-
addLayoutOnlyNodeToLayoutOnlyNode(parent, child, indexInNativeChildren);
266+
addLayoutOnlyNode(parent, child, indexInNativeChildren);
239267
}
240268
}
241269

@@ -262,73 +290,14 @@ private void removeNodeFromParent(ReactShadowNode nodeToRemove, boolean shouldDe
262290
}
263291
}
264292

265-
private void addLayoutOnlyNodeToLayoutOnlyNode(
266-
ReactShadowNode parent,
267-
ReactShadowNode child,
268-
int index) {
269-
ReactShadowNode parentParent = parent.getParent();
270-
271-
// If the parent hasn't been attached to its parent yet, don't issue commands to the native
272-
// hierarchy. We'll do that when the parent node actually gets attached somewhere.
273-
if (parentParent == null) {
274-
return;
275-
}
276-
277-
int transformedIndex = index + parentParent.getNativeOffsetForChild(parent);
278-
if (parentParent.isLayoutOnly()) {
279-
addLayoutOnlyNodeToLayoutOnlyNode(parentParent, child, transformedIndex);
280-
} else {
281-
addLayoutOnlyNodeToNonLayoutOnlyNode(parentParent, child, transformedIndex);
282-
}
283-
}
284-
285-
private void addNonLayoutOnlyNodeToLayoutOnlyNode(
286-
ReactShadowNode layoutOnlyNode,
287-
ReactShadowNode nonLayoutOnlyNode,
288-
int index) {
289-
ReactShadowNode parent = layoutOnlyNode.getParent();
290-
291-
// If the parent hasn't been attached to its parent yet, don't issue commands to the native
292-
// hierarchy. We'll do that when the parent node actually gets attached somewhere.
293-
if (parent == null) {
294-
return;
295-
}
296-
297-
int transformedIndex = index + parent.getNativeOffsetForChild(layoutOnlyNode);
298-
if (parent.isLayoutOnly()) {
299-
addNonLayoutOnlyNodeToLayoutOnlyNode(parent, nonLayoutOnlyNode, transformedIndex);
300-
} else {
301-
addNonLayoutNodeToNonLayoutNode(parent, nonLayoutOnlyNode, transformedIndex);
302-
}
303-
}
304-
305-
private void addLayoutOnlyNodeToNonLayoutOnlyNode(
293+
private void addLayoutOnlyNode(
306294
ReactShadowNode nonLayoutOnlyNode,
307295
ReactShadowNode layoutOnlyNode,
308296
int index) {
309-
// Add all of the layout-only node's children to its parent instead
310-
int currentIndex = index;
311-
for (int i = 0; i < layoutOnlyNode.getChildCount(); i++) {
312-
ReactShadowNode childToAdd = layoutOnlyNode.getChildAt(i);
313-
Assertions.assertCondition(childToAdd.getNativeParent() == null);
314-
315-
if (childToAdd.isLayoutOnly()) {
316-
// Adding this layout-only child could result in adding multiple native views
317-
int childCountBefore = nonLayoutOnlyNode.getNativeChildCount();
318-
addLayoutOnlyNodeToNonLayoutOnlyNode(
319-
nonLayoutOnlyNode,
320-
childToAdd,
321-
currentIndex);
322-
int childCountAfter = nonLayoutOnlyNode.getNativeChildCount();
323-
currentIndex += childCountAfter - childCountBefore;
324-
} else {
325-
addNonLayoutNodeToNonLayoutNode(nonLayoutOnlyNode, childToAdd, currentIndex);
326-
currentIndex++;
327-
}
328-
}
297+
addGrandchildren(nonLayoutOnlyNode, layoutOnlyNode, index);
329298
}
330299

331-
private void addNonLayoutNodeToNonLayoutNode(
300+
private void addNonLayoutNode(
332301
ReactShadowNode parent,
333302
ReactShadowNode child,
334303
int index) {
@@ -340,6 +309,31 @@ private void addNonLayoutNodeToNonLayoutNode(
340309
null);
341310
}
342311

312+
private void addGrandchildren(
313+
ReactShadowNode nativeParent,
314+
ReactShadowNode child,
315+
int index) {
316+
Assertions.assertCondition(!nativeParent.isLayoutOnly());
317+
318+
// `child` can't hold native children. Add all of `child`'s children to `parent`.
319+
int currentIndex = index;
320+
for (int i = 0; i < child.getChildCount(); i++) {
321+
ReactShadowNode grandchild = child.getChildAt(i);
322+
Assertions.assertCondition(grandchild.getNativeParent() == null);
323+
324+
if (grandchild.isLayoutOnly()) {
325+
// Adding this child could result in adding multiple native views
326+
int grandchildCountBefore = nativeParent.getNativeChildCount();
327+
addLayoutOnlyNode(nativeParent, grandchild, currentIndex);
328+
int grandchildCountAfter = nativeParent.getNativeChildCount();
329+
currentIndex += grandchildCountAfter - grandchildCountBefore;
330+
} else {
331+
addNonLayoutNode(nativeParent, grandchild, currentIndex);
332+
currentIndex++;
333+
}
334+
}
335+
}
336+
343337
private void applyLayoutBase(ReactShadowNode node) {
344338
int tag = node.getReactTag();
345339
if (mTagsWithLayoutVisited.get(tag)) {

0 commit comments

Comments
 (0)