Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LayoutAnimation crash on Android #27552

Closed
ydongzhu opened this issue Dec 17, 2019 · 35 comments
Closed

LayoutAnimation crash on Android #27552

ydongzhu opened this issue Dec 17, 2019 · 35 comments
Assignees
Labels
API: LayoutAnimation Bug p: Amazon Partner: Amazon Platform: Android Android applications. Stale There has been a lack of activity on this issue and it may be closed soon.

Comments

@ydongzhu
Copy link

ydongzhu commented Dec 17, 2019

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.:

  1. com.facebook.react.uimanager.IllegalViewOperationException: Trying to remove a view index above child count 0
    at com.facebook.react.uimanager.NativeViewHierarchyManager.manageChildren
    ...

  2. 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
    ...

  3. 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:

  1. 20b4879#diff-55b8191729d605b79bc0964d365ce96f
  2. 5f027ec#diff-55b8191729d605b79bc0964d365ce96f

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

Steps To Reproduce

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:

  1. Play the FlaList for a while which would trigger LayoutAnimation a couple of times
  2. Leave the current screen and then come back immediately
  3. Crash happens when application is trying to restore the previous state of this screen

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);
}

And code snippet in NativeViewHierarchyManager.manageChildren():

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

@ydongzhu ydongzhu added the Bug label Dec 17, 2019
@TheSavior TheSavior added the p: Amazon Partner: Amazon label Dec 18, 2019
@TheSavior
Copy link
Member

TheSavior commented Dec 18, 2019

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.

@ydongzhu
Copy link
Author

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.

@TheSavior
Copy link
Member

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.

@ydongzhu
Copy link
Author

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: ydongzhu@gmail.com

@evanyholm
Copy link

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.

@ydongzhu
Copy link
Author

@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.

@JoshuaGross
Copy link
Contributor

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.

@ydongzhu
Copy link
Author

@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.

@ydongzhu
Copy link
Author

@JoshuaGross is there any update for this issue? or any timeline or version we can expect to fix it?

@ydongzhu
Copy link
Author

@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.

@Niryo
Copy link

Niryo commented Feb 27, 2020

My team is struggling with issue number 3, react native 61
please update when you have new information about this

@JoshuaGross
Copy link
Contributor

@ydongzhu

I anticipate the following commits have fixed this crash, can you confirm?

c938c0a
d3b93f7
dedf937

@mgambati
Copy link

@JoshuaGross Tested the commits and it didn't work. Still receiving an IndexOutOfBoundsException.

@JoshuaGross
Copy link
Contributor

@mgambati Is your repro the same as @ydongzhu's? Do you have a Snack?

@mgambati
Copy link

@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.

@ydongzhu
Copy link
Author

ydongzhu commented Mar 30, 2020

@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:

  1. Building a patch for the three commits.
  2. Building a patch for ndk build error: #26314
  3. Applying these two patches to node_modules/react-native/ReactAndroid
  4. Following building-from-source to manually build ReactAndroid package so we have the changes that we want to test integrated.
  5. Run command 'npx react-native run-android' in terminal, and then tap 'HACK' button, you will see the crash happening.
    (You only need to modify local.properties file when checkout test-patch branch and then run the command since I've applied both of the patches already)

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.

@kulikalov
Copy link

Looks like no one is working on this? Meanwhile, is there any good substitute to create a properly animated flat list?

@ydongzhu
Copy link
Author

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.

@georgeMorales
Copy link

same problem on android index=15 count=14

@evelant
Copy link

evelant commented Sep 6, 2020

@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
Copy link
Author

ydongzhu commented Sep 8, 2020

@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 .

@jocoders
Copy link

Every week get crashlytics report with this issue on Android 10(Samsung, Xiaomi, Huawei, LGE). Any news?

@lcarrettin
Copy link

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.

int normalizedIndex = viewAtIndex.mIndex;
if (!pendingDeletionTags.isEmpty()) {
normalizedIndex = 0;
int counter = 0;
while (normalizedIndex < viewToManage.getChildCount()) {
if (counter == viewAtIndex.mIndex) {
break;
}
View v = viewToManage.getChildAt(normalizedIndex);
if (!pendingDeletionTags.contains(v.getId())) {
counter++;
}
normalizedIndex++;
}
}
viewManager.addView(viewToManage, viewToAdd, normalizedIndex);

@paradite
Copy link

paradite commented Jan 24, 2021

Same issue here. I can reliably reproduce this issue with repeated addition and removal of elements from a list of Views.

It doesn't seem to be related to the duration of the animation as I still get errors related to indices even with animation duration (20ms) way lower than the interval of triggering (2s).

Update: Didn't want to be stuck with this issue, so I took some time to refactor my code from LayoutAnimation to Animated (with dynamically generated data), and everything works now. The tricky part of the dynamically generated data is that the refs needs to be in child components, not the parent. Hope it helps whoever is having issue with this LayoutAnimation bug until it is fixed.

@briefjudofox
Copy link

I don't think this is adding anything new to the conversation, but we also started seeing this crash when going from RN 0.61 to 0.63. We had to remove UIManager.setLayoutAnimationEnabledExperimental(true); to avoid the crash.

@chuganzy
Copy link
Contributor

chuganzy commented Apr 1, 2021

This started to happen to us after upgrading to 0.64.0.

@evelant
Copy link

evelant commented May 25, 2021

Had to disable layoutanimations on Android due to this. I think @lcarrettin may be right about the underlying cause but I don't have the native android experience to attempt a PR with a fix.

@djMax
Copy link

djMax commented Oct 27, 2021

We are able to reliably reproduce this in our app, though it's a fairly complex one. How can we be helpful?

@robertwt7
Copy link

Hey peeps, this is still happening for us as well..

Affects thousands of users only on android

I think this affect a lot of other people as well, currently this is the only fix working for us:
https://stackoverflow.com/questions/41819759/trying-to-remove-a-view-index-above-child-count-error

@LeviWilliams
Copy link

Still happening to us as well, we have a pager view and an easeIn/Out layout animation will frequently crash it.

@stopachka
Copy link

I came across this issue as well. Right now, I solve it, by using reanimated layout animations in Android.

@nes123
Copy link

nes123 commented Feb 28, 2022

I don't think this is adding anything new to the conversation, but we also started seeing this crash when going from RN 0.61 to 0.63. We had to remove UIManager.setLayoutAnimationEnabledExperimental(true); to avoid the crash.

Can someone confirm that it works?

@robertwt7
Copy link

It seems like it is also causing an issue on the LayoutAnimation presets from react-native-reanimated,

related to this issue for us: software-mansion/react-native-reanimated#3234

@github-actions
Copy link

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

@github-actions github-actions bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Mar 29, 2023
@github-actions
Copy link

github-actions bot commented Apr 5, 2023

This issue was closed because it has been stalled for 7 days with no activity.

@github-actions github-actions bot closed this as completed Apr 5, 2023
@facebook facebook locked as resolved and limited conversation to collaborators Apr 5, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
API: LayoutAnimation Bug p: Amazon Partner: Amazon Platform: Android Android applications. Stale There has been a lack of activity on this issue and it may be closed soon.
Projects
None yet
Development

No branches or pull requests