We've addressed 3 crashes so far that are related to LayoutAnimation while we are using RN 59.8 release in our app and each of them is impacting our users a lot.:
com.facebook.react.uimanager.IllegalViewOperationException: Trying to remove a view index above child count 0
at com.facebook.react.uimanager.NativeViewHierarchyManager.manageChildren
...
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
...
at android.view.ViewGroup.addView
at com.facebook.react.uimanager.ViewGroupManager.addView
at com.facebook.react.uimanager.NativeViewHierarchyManager.manageChildren
...
java.lang.IndexOutOfBoundsException: index=28 count=27
...
at android.view.ViewGroup.addView
at com.facebook.react.uimanager.ViewGroupManager.addView
at com.facebook.react.uimanager.NativeViewHierarchyManager.manageChildren
...
We've also noticed there are a couple of commits trying to fix these crashes after 59.8 release and two of them are eventually merged:
which are built in the patch that we are going to apply to our app as well. This patch significantly reduces the chance of the first and third crashes happening, but it's still able to reproduce the second one, 'java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first'.
Since it's not easy to describe all details here, there is a collated document attached to this ticket that includes everything about the crash, e.g. stack trace, customized log and relevant code snippet.
React Native version:
59.8
We are using FlatList to wrap a list of cards and applying LayoutAnimation to it when state of content changes. Here is how we setup LayoutAnimation in JS code:
update: {
type: LayoutAnimation.Types.linear,
property: LayoutAnimation.Properties.scaleXY,
duration: xxx,
},
delete: {
type: LayoutAnimation.Types.linear,
property: LayoutAnimation.Properties.opacity,
duration: xxx,
},
From our scenario, the steps to reproduce are:
Describe what you expected to happen:
Everything should be fine, no crash happens at least.
Snack, code example, screenshot, or link to a repository:
Here are some critical logs when the crash happens:
Optimizer, addNonLayoutNode, parent = 4905, child = 4493, index = 0
Optimizer, addNonLayoutNode, parent = 4905, child = 4493, index = 0
Optimizer, addNonLayoutNode, parent = 4905, child = 4539, index = 1
Optimizer, addNonLayoutNode, parent = 4905, child = 4539, index = 1
Optimizer, addNonLayoutNode, parent = 4905, child = 4587, index = 2
Optimizer, addNonLayoutNode, parent = 4905, child = 4587, index = 2
Optimizer, addNonLayoutNode, parent = 4905, child = 4635, index = 3
Optimizer, addNonLayoutNode, parent = 4905, child = 4635, index = 3
Optimizer, addNonLayoutNode, parent = 4905, child = 4683, index = 4
Optimizer, addNonLayoutNode, parent = 4905, child = 4683, index = 4
Optimizer, addNonLayoutNode, parent = 4905, child = 4729, index = 5
Optimizer, addNonLayoutNode, parent = 4905, child = 4729, index = 5
Optimizer, addNonLayoutNode, parent = 4905, child = 4777, index = 6
Optimizer, addNonLayoutNode, parent = 4905, child = 4777, index = 6
Optimizer, addNonLayoutNode, parent = 4905, child = 4825, index = 7
Optimizer, addNonLayoutNode, parent = 4905, child = 4825, index = 7
Optimizer, addNonLayoutNode, parent = 4905, child = 4863, index = 8
Optimizer, addNonLayoutNode, parent = 4905, child = 4863, index = 8
Optimizer, addNonLayoutNode, parent = 4905, child = 4899, index = 9
Optimizer, addNonLayoutNode, parent = 4905, child = 4899, index = 9
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [], atIndices: [], removeFrom: [5], tag = 4905
going to add view, tag = 4785, at 0
Optimizer, removeNodeFromParent, parent = 4905, tag = 4729, delete = true
going to add view, tag = 4787, at 0
Optimizer, removeNodeFromParent, parent = 4905, tag = 4729, delete = true
going to add view, tag = 4793, at 1
Optimizer, removeNodeFromParent, parent = 4905, tag = 4729, delete = true
going to add view, tag = 4779, at 0
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [], atIndices: [], removeFrom: [5], tag = 4905
Optimizer, removeNodeFromParent, parent = 4905, tag = 4777, delete = true
going to add view, tag = 4783, at 1
Optimizer, removeNodeFromParent, parent = 4905, tag = 4777, delete = true
going to add view, tag = 4795, at 2
Optimizer, removeNodeFromParent, parent = 4905, tag = 4777, delete = true
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [], atIndices: [], removeFrom: [5], tag = 4905
going to add view, tag = 4803, at 0
Optimizer, removeNodeFromParent, parent = 4905, tag = 4825, delete = true
going to add view, tag = 4807, at 1
Optimizer, removeNodeFromParent, parent = 4905, tag = 4825, delete = true
going to add view, tag = 4813, at 2
Optimizer, removeNodeFromParent, parent = 4905, tag = 4825, delete = true
going to add view, tag = 4817, at 0
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [], atIndices: [], removeFrom: [5], tag = 4905
Optimizer, removeNodeFromParent, parent = 4905, tag = 4863, delete = true
going to add view, tag = 4827, at 0
Optimizer, removeNodeFromParent, parent = 4905, tag = 4863, delete = true
going to add view, tag = 4829, at 1
Optimizer, removeNodeFromParent, parent = 4905, tag = 4863, delete = true
going to add view, tag = 4839, at 0
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [], atIndices: [], removeFrom: [5], tag = 4905
Optimizer, removeNodeFromParent, parent = 4905, tag = 4899, delete = true
going to add view, tag = 4845, at 1
Optimizer, removeNodeFromParent, parent = 4905, tag = 4899, delete = true
going to add view, tag = 4849, at 2
Optimizer, removeNodeFromParent, parent = 4905, tag = 4899, delete = true
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [0], moveTo: [1], addTags: [], atIndices: [], removeFrom: [], tag = 4905
Optimizer, removeNodeFromParent, parent = 4905, tag = 4493, delete = false
going to add view, tag = 4867, at 1
Optimizer, removeNodeFromParent, parent = 4905, tag = 4493, delete = false
going to add view, tag = 4877, at 0
Optimizer, addNonLayoutNode, parent = 4905, child = 4493, index = 1
going to add view, tag = 4883, at 1
Optimizer, addNonLayoutNode, parent = 4905, child = 4493, index = 1
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [5029], atIndices: [3], removeFrom: [], tag = 4905
going to add view, tag = 4729, at 5
Optimizer, addNonLayoutNode, parent = 4905, child = 5029, index = 3
going to add view, tag = 4777, at 6
Optimizer, addNonLayoutNode, parent = 4905, child = 5029, index = 3
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [5069], atIndices: [5], removeFrom: [], tag = 4905
Optimizer, addNonLayoutNode, parent = 4905, child = 5069, index = 5
Optimizer, addNonLayoutNode, parent = 4905, child = 5069, index = 5
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [5109], atIndices: [7], removeFrom: [], tag = 4905
going to add view, tag = 4949, at 1
Optimizer, addNonLayoutNode, parent = 4905, child = 5109, index = 7
going to add view, tag = 4957, at 0
Optimizer, addNonLayoutNode, parent = 4905, child = 5109, index = 7
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [5147], atIndices: [8], removeFrom: [], tag = 4905
Optimizer, addNonLayoutNode, parent = 4905, child = 5147, index = 8
remove view at 0, normalized index = 0, tag = 4425, parent tag = 4427
going to add view, tag = 4927, at 0
Optimizer, addNonLayoutNode, parent = 4905, child = 5147, index = 8
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [5185], atIndices: [9], removeFrom: [], tag = 4905
going to add view, tag = 4959, at 1
Optimizer, addNonLayoutNode, parent = 4905, child = 5185, index = 9
Optimizer, addNonLayoutNode, parent = 4905, child = 5185, index = 9
remove view at 0, normalized index = 0, tag = 4493, parent tag = 4905
going to add view, tag = 4493, at 1
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [5247], atIndices: [10], removeFrom: [], tag = 4905
Optimizer, addNonLayoutNode, parent = 4905, child = 5247, index = 10
Optimizer, addNonLayoutNode, parent = 4905, child = 5247, index = 10
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [5285], atIndices: [11], removeFrom: [], tag = 4905
Optimizer, addNonLayoutNode, parent = 4905, child = 5285, index = 11
Optimizer, addNonLayoutNode, parent = 4905, child = 5285, index = 11
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [5323], atIndices: [12], removeFrom: [], tag = 4905
Optimizer, addNonLayoutNode, parent = 4905, child = 5323, index = 12
Optimizer, addNonLayoutNode, parent = 4905, child = 5323, index = 12
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [5359], atIndices: [13], removeFrom: [], tag = 4905
Optimizer, addNonLayoutNode, parent = 4905, child = 5359, index = 13
Optimizer, addNonLayoutNode, parent = 4905, child = 5359, index = 13
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [5397], atIndices: [14], removeFrom: [], tag = 4905
Optimizer, addNonLayoutNode, parent = 4905, child = 5397, index = 14
Optimizer, addNonLayoutNode, parent = 4905, child = 5397, index = 14
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [5435], atIndices: [15], removeFrom: [], tag = 4905
Optimizer, addNonLayoutNode, parent = 4905, child = 5435, index = 15
Optimizer, addNonLayoutNode, parent = 4905, child = 5435, index = 15
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [5473], atIndices: [16], removeFrom: [], tag = 4905
Optimizer, addNonLayoutNode, parent = 4905, child = 5473, index = 16
Optimizer, addNonLayoutNode, parent = 4905, child = 5473, index = 16
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [5509], atIndices: [17], removeFrom: [], tag = 4905
Optimizer, addNonLayoutNode, parent = 4905, child = 5509, index = 17
Optimizer, addNonLayoutNode, parent = 4905, child = 5509, index = 17
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [5547], atIndices: [18], removeFrom: [], tag = 4905
Optimizer, addNonLayoutNode, parent = 4905, child = 5547, index = 18
Optimizer, addNonLayoutNode, parent = 4905, child = 5547, index = 18
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [5585], atIndices: [19], removeFrom: [], tag = 4905
Optimizer, addNonLayoutNode, parent = 4905, child = 5585, index = 19
Optimizer, addNonLayoutNode, parent = 4905, child = 5585, index = 19
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [], atIndices: [], removeFrom: [20], tag = 4905
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [5623], atIndices: [20], removeFrom: [], tag = 4905
remove view at 0, normalized index = 0, tag = 5113, parent tag = 5125
Optimizer, addNonLayoutNode, parent = 4905, child = 5623, index = 20
Optimizer, addNonLayoutNode, parent = 4905, child = 5623, index = 20
remove view at 0, normalized index = 0, tag = 5149, parent tag = 5163
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [5659], atIndices: [21], removeFrom: [], tag = 4905
Optimizer, addNonLayoutNode, parent = 4905, child = 5659, index = 21
Optimizer, addNonLayoutNode, parent = 4905, child = 5659, index = 21
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [5697], atIndices: [22], removeFrom: [], tag = 4905
Optimizer, addNonLayoutNode, parent = 4905, child = 5697, index = 22
Optimizer, addNonLayoutNode, parent = 4905, child = 5697, index = 22
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [5735], atIndices: [23], removeFrom: [], tag = 4905
Optimizer, addNonLayoutNode, parent = 4905, child = 5735, index = 23
Optimizer, addNonLayoutNode, parent = 4905, child = 5735, index = 23
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [], moveTo: [], addTags: [5769], atIndices: [24], removeFrom: [], tag = 4905
Optimizer, addNonLayoutNode, parent = 4905, child = 5769, index = 24
Optimizer, addNonLayoutNode, parent = 4905, child = 5769, index = 24
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [1], moveTo: [17], addTags: [], atIndices: [], removeFrom: [], tag = 4905
Optimizer, removeNodeFromParent, parent = 4905, tag = 4493, delete = false
Optimizer, removeNodeFromParent, parent = 4905, tag = 4493, delete = false
Optimizer, addNonLayoutNode, parent = 4905, child = 4493, index = 17
Optimizer, addNonLayoutNode, parent = 4905, child = 4493, index = 17
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [0], moveTo: [17], addTags: [], atIndices: [], removeFrom: [], tag = 4905
Optimizer, removeNodeFromParent, parent = 4905, tag = 4539, delete = false
Optimizer, removeNodeFromParent, parent = 4905, tag = 4539, delete = false
Optimizer, addNonLayoutNode, parent = 4905, child = 4539, index = 17
Optimizer, addNonLayoutNode, parent = 4905, child = 4539, index = 17
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [0], moveTo: [17], addTags: [], atIndices: [], removeFrom: [], tag = 4905
Optimizer, removeNodeFromParent, parent = 4905, tag = 4587, delete = false
Optimizer, removeNodeFromParent, parent = 4905, tag = 4587, delete = false
Optimizer, addNonLayoutNode, parent = 4905, child = 4587, index = 17
Optimizer, addNonLayoutNode, parent = 4905, child = 4587, index = 17
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [0], moveTo: [17], addTags: [], atIndices: [], removeFrom: [], tag = 4905
Optimizer, removeNodeFromParent, parent = 4905, tag = 5029, delete = false
Optimizer, removeNodeFromParent, parent = 4905, tag = 5029, delete = false
Optimizer, addNonLayoutNode, parent = 4905, child = 5029, index = 17
Optimizer, addNonLayoutNode, parent = 4905, child = 5029, index = 17
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [0], moveTo: [17], addTags: [], atIndices: [], removeFrom: [], tag = 4905
Optimizer, removeNodeFromParent, parent = 4905, tag = 4635, delete = false
Optimizer, removeNodeFromParent, parent = 4905, tag = 4635, delete = false
Optimizer, addNonLayoutNode, parent = 4905, child = 4635, index = 17
Optimizer, addNonLayoutNode, parent = 4905, child = 4635, index = 17
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [0], moveTo: [17], addTags: [], atIndices: [], removeFrom: [], tag = 4905
Optimizer, removeNodeFromParent, parent = 4905, tag = 5069, delete = false
Optimizer, removeNodeFromParent, parent = 4905, tag = 5069, delete = false
Optimizer, addNonLayoutNode, parent = 4905, child = 5069, index = 17
Optimizer, addNonLayoutNode, parent = 4905, child = 5069, index = 17
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [0], moveTo: [17], addTags: [], atIndices: [], removeFrom: [], tag = 4905
Optimizer, removeNodeFromParent, parent = 4905, tag = 4683, delete = false
Optimizer, removeNodeFromParent, parent = 4905, tag = 4683, delete = false
Optimizer, addNonLayoutNode, parent = 4905, child = 4683, index = 17
Optimizer, addNonLayoutNode, parent = 4905, child = 4683, index = 17
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [0], moveTo: [17], addTags: [], atIndices: [], removeFrom: [], tag = 4905
Optimizer, removeNodeFromParent, parent = 4905, tag = 5109, delete = false
Optimizer, removeNodeFromParent, parent = 4905, tag = 5109, delete = false
Optimizer, addNonLayoutNode, parent = 4905, child = 5109, index = 17
Optimizer, addNonLayoutNode, parent = 4905, child = 5109, index = 17
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [0], moveTo: [17], addTags: [], atIndices: [], removeFrom: [], tag = 4905
Optimizer, removeNodeFromParent, parent = 4905, tag = 5147, delete = false
Optimizer, removeNodeFromParent, parent = 4905, tag = 5147, delete = false
Optimizer, addNonLayoutNode, parent = 4905, child = 5147, index = 17
Optimizer, addNonLayoutNode, parent = 4905, child = 5147, index = 17
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [0], moveTo: [17], addTags: [], atIndices: [], removeFrom: [], tag = 4905
Optimizer, removeNodeFromParent, parent = 4905, tag = 5185, delete = false
Optimizer, removeNodeFromParent, parent = 4905, tag = 5185, delete = false
Optimizer, addNonLayoutNode, parent = 4905, child = 5185, index = 17
Optimizer, addNonLayoutNode, parent = 4905, child = 5185, index = 17
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [0], moveTo: [17], addTags: [], atIndices: [], removeFrom: [], tag = 4905
Optimizer, removeNodeFromParent, parent = 4905, tag = 5247, delete = false
Optimizer, removeNodeFromParent, parent = 4905, tag = 5247, delete = false
Optimizer, addNonLayoutNode, parent = 4905, child = 5247, index = 17
Optimizer, addNonLayoutNode, parent = 4905, child = 5247, index = 17
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [0], moveTo: [17], addTags: [], atIndices: [], removeFrom: [], tag = 4905
Optimizer, removeNodeFromParent, parent = 4905, tag = 5285, delete = false
Optimizer, removeNodeFromParent, parent = 4905, tag = 5285, delete = false
Optimizer, addNonLayoutNode, parent = 4905, child = 5285, index = 17
Optimizer, addNonLayoutNode, parent = 4905, child = 5285, index = 17
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [0], moveTo: [17], addTags: [], atIndices: [], removeFrom: [], tag = 4905
Optimizer, removeNodeFromParent, parent = 4905, tag = 5323, delete = false
Optimizer, removeNodeFromParent, parent = 4905, tag = 5323, delete = false
Optimizer, addNonLayoutNode, parent = 4905, child = 5323, index = 17
Optimizer, addNonLayoutNode, parent = 4905, child = 5323, index = 17
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [0], moveTo: [17], addTags: [], atIndices: [], removeFrom: [], tag = 4905
Optimizer, removeNodeFromParent, parent = 4905, tag = 5359, delete = false
Optimizer, removeNodeFromParent, parent = 4905, tag = 5359, delete = false
Optimizer, addNonLayoutNode, parent = 4905, child = 5359, index = 17
Optimizer, addNonLayoutNode, parent = 4905, child = 5359, index = 17
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [0], moveTo: [17], addTags: [], atIndices: [], removeFrom: [], tag = 4905
Optimizer, removeNodeFromParent, parent = 4905, tag = 5397, delete = false
Optimizer, removeNodeFromParent, parent = 4905, tag = 5397, delete = false
Optimizer, addNonLayoutNode, parent = 4905, child = 5397, index = 17
Optimizer, addNonLayoutNode, parent = 4905, child = 5397, index = 17
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [0], moveTo: [17], addTags: [], atIndices: [], removeFrom: [], tag = 4905
Optimizer, removeNodeFromParent, parent = 4905, tag = 5435, delete = false
Optimizer, removeNodeFromParent, parent = 4905, tag = 5435, delete = false
Optimizer, addNonLayoutNode, parent = 4905, child = 5435, index = 17
Optimizer, addNonLayoutNode, parent = 4905, child = 5435, index = 17
------------------ (UIManager.manageChildren) tag: 4905, moveFrom: [0], moveTo: [17], addTags: [], atIndices: [], removeFrom: [], tag = 4905
Optimizer, removeNodeFromParent, parent = 4905, tag = 5473, delete = false
Optimizer, removeNodeFromParent, parent = 4905, tag = 5473, delete = false
Optimizer, addNonLayoutNode, parent = 4905, child = 5473, index = 17
Optimizer, addNonLayoutNode, parent = 4905, child = 5473, index = 17
remove view at 1, normalized index = 1, tag = 4493, parent tag = 4905
going to add view, tag = 4493, at 17
remove view at 0, normalized index = 0, tag = 4539, parent tag = 4905
going to add view, tag = 4539, at 17
remove view at 0, normalized index = 0, tag = 4587, parent tag = 4905
going to add view, tag = 4587, at 17
remove view at 0, normalized index = 0, tag = 5029, parent tag = 4905
going to add view, tag = 5029, at 17
remove view at 0, normalized index = 0, tag = 4635, parent tag = 4905
going to add view, tag = 4635, at 17
remove view at 0, normalized index = 0, tag = 4683, parent tag = 4905
going to add view, tag = 5069, at 17
These logs reflect the whole flow of the crash happening. To help understanding, view 4905 is the view container of the list which is _ReactHorizontalScrollContainerView_ on Android, and crash happens at the last line when adds view 5069, which already has a parent, into view 4905 at index 17.
The code run into this situation due to inconsistent view hierarchy state between _ReactShadowNode_ and _NativeViewHierarchyManager_ when there are pending deletion animations.
In _UIImplementation_, views will be added into the latest view hierarchy without any pending state calculation, but it does consider the pending state if the index of the view to be added is equal to or larger than the starting position of deleting items in _NativeViewHierarchyManager_.
Relevant code snippet in _UIImplementation.manageChildren()_:
if (numToMove > 0) {
Assertions.assertNotNull(moveFrom);
Assertions.assertNotNull(moveTo);
for(lastIndexRemoved = 0; lastIndexRemoved < numToMove; ++lastIndexRemoved) {
i = moveFrom.getInt(lastIndexRemoved);
indexToRemove = cssNodeToManage.getChildAt(i).getReactTag();
viewsToAdd[lastIndexRemoved] = new ViewAtIndex(indexToRemove, moveTo.getInt(lastIndexRemoved));
indicesToRemove[lastIndexRemoved] = i;
tagsToRemove[lastIndexRemoved] = indexToRemove;
}
}
if (numToAdd > 0) {
Assertions.assertNotNull(addChildTags);
Assertions.assertNotNull(addAtIndices);
for(lastIndexRemoved = 0; lastIndexRemoved < numToAdd; ++lastIndexRemoved) {
i = addChildTags.getInt(lastIndexRemoved);
indexToRemove = addAtIndices.getInt(lastIndexRemoved);
viewsToAdd[numToMove + lastIndexRemoved] = new ViewAtIndex(i, indexToRemove);
}
}
for(i = 0; i < viewsToAdd.length; ++i) {
ViewAtIndex viewAtIndex = viewsToAdd[i];
ReactShadowNode cssNodeToAdd = this.mShadowNodeRegistry.getNode(viewAtIndex.mTag);
if (cssNodeToAdd == null) {
throw new IllegalViewOperationException("Trying to add unknown view tag: " + viewAtIndex.mTag);
}
cssNodeToManage.addChildAt(cssNodeToAdd, viewAtIndex.mIndex);
}
md5-38b059dacf895aebaed58e2a9a26f3a6
if (viewsToAdd != null) {
for(i = 0; i < viewsToAdd.length; ++i) {
ViewAtIndex viewAtIndex = viewsToAdd[i];
View viewToAdd = (View)this.mTagsToViews.get(viewAtIndex.mTag);
if (viewToAdd == null) {
throw new IllegalViewOperationException("Trying to add unknown view tag: " + viewAtIndex.mTag + "\n detail: " + constructManageChildrenErrorMessage(viewToManage, viewManager, indicesToRemove, viewsToAdd, tagsToDelete));
}
int normalizedIndexToAdd = this.normalizeIndex(viewAtIndex.mIndex, pendingIndicesToDelete);
viewManager.addView(viewToManage, viewToAdd, normalizedIndexToAdd);
}
}
To help understanding, there is a picture shows the crash flow in the attached doc.
Issue of applying the patch to fix LayoutAnimation on Android.pdf
Thanks for sharing the investigation!
Can you edit your post to include the contents of your PDF? That will make it so that people searching for this bug in the future can be more likely to find this.
I think we are aware of a couple of long standing crashes with LayoutAnimation on Android but haven't been able to figure out how to repro or track it down.
Do you have a small reproducible test case for this bug? That would be very helpful for us to figure out what's happening.
Hi @TheSavior I updated the issue to include most of the details about the crash, sorry I don't have a reproducible test case to share, I mainly use our own app to reproduce it and am not allowed to share the code to you.
We use LayoutAnimation in a regular way, no special handling to it actually. Theoretically this crash would happen in any code that using Delete LayoutAnimation, so I don't think it's a corner case to our own code.
If you don’t think it’s special to your codebase, would you be willing to spend some time creating a minimal repro case in an app outside of Amazon? Likely by creating a new app with react-native init?
This would be important for us to be able to investigate and fix.
Hi @TheSavior, I would love to create repro case in a brand new app to help investigating this issue, but I am working on a different project now, so I may not be able to work on that very soon.
The doc I attached contains all information about the crash and explains why it happens as well, may be you could start from there first. I can't estimate now how much time I need to finish it, but I will be working on it whenever I can.
Please contact me if any questions you have about this issue: [email protected]
Hi, Im getting the exact same error number two with using draggable flatlist from https://github.com/computerjazz/react-native-draggable-flatlist.
When deleting one item from the list and then dragging and dropping any of the items left, it eventually will crash randomly.
@TheSavior I've built a test app to reproduce the crash, see here https://github.com/ydongzhu/create-react-native-app
Run command 'npx react-native run-android' in terminal, and then tap 'HACK' button, you will see the crash happening.
FWIW, in the future it seems like this could be packaged as a snack and would make it easier for us to quickly repro. I was able to copy App.js into a playground locally and repro this crash.
Also though, if I just tap the "HACK" button, it doesn't crash. I need to interact with the screen and scroll around. It's generally pretty easy to find a crash, but the repro steps are complex enough that it will take a while to figure out what's wrong.
@JoshuaGross when you tap the 'HACK' button, what it's doing is actually repro the condition that puts the app into crash-ready state and then perform a regular view manipulation to trigger it. There will be one second delay to trigger the crash, so it doesn't happen immediately.
The core part of repro the crash is manipulating views before deletion animation is finished. So you will see in the code that I manually set the duration of delete animation with 15 seconds to give enough time to do following view manipulation. You can modify the code to do whatever test you want as well.
Please refer to the pdf attached in this issue, it has detailed explanation about the reason.
@JoshuaGross is there any update for this issue? or any timeline or version we can expect to fix it?
@JoshuaGross After reaching out to your team, we're going to move forward to look into this issue ourselves first and try to fix it. We will let you know if any questions we have and when there is a pull request for it as well.
My team is struggling with issue number 3, react native 61
please update when you have new information about this
@ydongzhu
I anticipate the following commits have fixed this crash, can you confirm?
https://github.com/facebook/react-native/commit/c938c0afbfbd0e5ba8853feb212a976f605f51f0
https://github.com/facebook/react-native/commit/d3b93f75787267629c4033a5aa61b62d623f3c08
https://github.com/facebook/react-native/commit/dedf9372cae89d119930a8a2c33b337b6658bff2
@JoshuaGross Tested the commits and it didn't work. Still receiving an IndexOutOfBoundsException.
@mgambati Is your repro the same as @ydongzhu's? Do you have a Snack?
@JoshuaGross Tried my best to reproduce the bug on a snack with a similar code that was on my app but still no success. This bug is really hard to reproduce, it's kinda random. It's just refuse to happen on the snack, I don't know if it's because of expo.
I'm going to try patching @ydongzhu repository with the commits to see if it solves.
@JoshuaGross I've done the test with those three commits last week, sorry for the late response.
Unfortunately there is an IndexOutOfBoundsException when testing those commits, which @mgambati mentioned above, I can easily reproduce it with the same test app that I used before, please checkout test-patch branch for testing from https://github.com/ydongzhu/create-react-native-app.
Here is how I integrated those commits and tested it:
I've also debugged the code a little bit, the reason why IndexOutOfBoundsException happens is that pending deletion animations are not finished before manipulating children in dedf937. This issue will be gone if onAnimationEnd() is executed immediately when invoke Animation.cancel(), however it is posted into main thread's message queue and mess up the order of manipulating children when it's executed in the end.
Looks like no one is working on this? Meanwhile, is there any good substitute to create a properly animated flat list?
Looks like no one is working on this? Meanwhile, is there any good substitute to create a properly animated flat list?
I guess this issue is not the priority of FB team for now so they just leave it here, I've not had any update for months.
same problem on android index=15 count=14
@ydongzhu did you ever make any progress on this one? I think we're encountering the same or similar issue (although we don't use layoutAnimation, we heavily use animations).
@ydongzhu did you ever make any progress on this one? I think we're encountering the same or similar issue (although we don't use layoutAnimation, we heavily use animations).
Unfortunately I haven't been actively working on this issue for a while, I had to move to other projects while I was waiting for the response. I'd like to rely on FB to fix it first since they had some progress on it already, from my opinion probably they just need to find a more robust way to solve the problem so all of cases, including the one that I pointed out in their commits, would be handled properly .
Every week get crashlytics report with this issue on Android 10(Samsung, Xiaomi, Huawei, LGE). Any news?
I’m testing my app after upgrading from RN 0.62.2 to 0.63.3 and randomly it crashes with
java.lang.IndexOutOfBoundsException: index=5 count=4
The error seems to be related to this commit, where the "index adjustment fix" was removed.
Looking at the code in NativeViewHierarchyManager.java where the crash originates (line 507), is it correct that in the preceding lines (from 491) there is an index “normalization” check only if there are pending deletions?
Obviously there aren’t pending deletions in my case, otherwise normalizedIndex would be <= viewToManage.getChildCount() and there wouldn’t be any crash.
Most helpful comment
@TheSavior I've built a test app to reproduce the crash, see here https://github.com/ydongzhu/create-react-native-app
Run command 'npx react-native run-android' in terminal, and then tap 'HACK' button, you will see the crash happening.