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

Add workaround for android API 33 ANR when inverting ScrollView #37913

Closed

Conversation

hannojg
Copy link
Contributor

@hannojg hannojg commented Jun 15, 2023

Summary:

As explained in this issue:

starting from android API 33 there are severe performance issues when using scaleY: -1 on a view, and its child view, which is what we are doing when inverting the ScrollView component (e.g. in FlatList).

This PR adds a workaround. The workaround is to also scale on the X-Axis which causes a different transform matrix to be created, that doesn't cause the ANR (see the issue for details).
However, when doing that the vertical scroll bar will be on the wrong side, thus we switch the position in the native code once we detect that the list is inverted.

The goal of this PR is that react-native users can just use <FlatList inverted={true} /> without running into any ANRs or the need to apply manual hot fixes 😄

Changelog:

[ANDROID] [FIXED] - ANR when having an inverted FlatList on android API 33+

Test Plan:

  • The change is minimal, and only affects android.
  • Run the RNTesterApp for android and confirm that in the flatlist example the inverted list is still working as expected.

@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jun 15, 2023
@analysis-bot
Copy link

Platform Engine Arch Size (bytes) Diff
android hermes arm64-v8a 8,757,479 -204
android hermes armeabi-v7a 8,070,058 -198
android hermes x86 9,250,082 -194
android hermes x86_64 9,099,221 -195
android jsc arm64-v8a 9,319,056 +227
android jsc armeabi-v7a 8,508,955 +219
android jsc x86 9,382,540 +223
android jsc x86_64 9,635,790 +226

Base commit: 7d4f233
Branch: main

@NickGerleman
Copy link
Contributor

Thanks for the PR! I'm going to pass this over to @rozele who has spent a lot of time fighting with inverted FlatList, to get his take.

There is some later work we have been potentially looking at to move away from inversion based on transform (this fixes a couple other issues, like Talkback not working correctly). This issue has been raised super often though, so we definitely shouldn't block on that if we have a reliable workaround to the Android platform issue.

Comment on lines +394 to +398
if (inverted) {
view.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_LEFT);
} else {
view.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_DEFAULT);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this work correctly for horizontal lists?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, does it position the scrollbar correctly on RTL interfaces?

I don't know offhand if they're usually on the opposite sides for RTL vs LTR on Android but I suspect they might be, they are for the web: https://www.w3.org/People/kennyluck/Test/bidi-scrollbar

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about RTL as well, but it seems that RTL isn't handled right now and the scrollbar handle is always on the right side. So I didn't add support for it here either.

HorizontalLists are handled by ReactHorizontalScrollViewManager, so yes, it still works 😊

transform: [{scaleY: -1}],
transform:
// It's important to invert the Y AND X axis to prevent a react native issue that can lead to ANRs on android 13
Platform.OS === 'android' ? [{scaleX: -1}, {scaleY: -1}] : [{scaleY: -1}],
},
horizontallyInverted: {
transform: [{scaleX: -1}],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the same workaround needed for horizontal lists?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Horizontal lists don't need that workaround, there won't be any ANRs when inverted

Copy link
Contributor

@rozele rozele left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments

@hannojg hannojg requested a review from rozele June 16, 2023 14:14
@facebook-github-bot
Copy link
Contributor

@NickGerleman has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@facebook-github-bot
Copy link
Contributor

@NickGerleman has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@github-actions
Copy link

This pull request was successfully merged by @hannojg in 90186cd.

When will my fix make it into a release? | Upcoming Releases

@github-actions github-actions bot added the Merged This PR has been merged. label Jun 22, 2023
@ejain
Copy link

ejain commented Jun 22, 2023

Will this fix make it into a 0.70.x release?

@NickGerleman
Copy link
Contributor

I would like for us to live with this change for a bit before we pick.

We should get feedback soon from Meta usages, but it wouldn’t hurt to also get RC validation. Though the timing with the release window would make that a long gap.

cc @cortinico who has followed the inverted flat list/chat ui perf issues.

@NickGerleman
Copy link
Contributor

NickGerleman commented Jun 22, 2023

I took a closer look at this change and found a couple issues, one of which would lead to a regression. I tried to find a short fix, but am unlanding for now instead.

The main one, is that RN internally may ship JS changes before native changes. This means we have a configuration where VirtualizedList uses scale instead of scaleY, but the new code in the ViewManager isn't yet running. We will need to either ship the native change first, or add a signal to read in JS. I would recommend the first since I think the API for view manager constants is in flux I think.

The other issue, that is more cosmetic is around types. Right now we pass every VirtualizedListProps prop to the ScrollView, and suppress type-checking. But we should be adding inverted to the props in ScrollViewNativeComponent if we are going to start passing it. Though I saw it was already part of the View Config.

@facebook-github-bot
Copy link
Contributor

This pull request has been reverted by f544376.

@hannojg
Copy link
Contributor Author

hannojg commented Jun 22, 2023

@NickGerleman thanks for examining this closely! What are the next steps here?
Should I make a change to the PR so the issue you named gets handled correctly?

@NickGerleman
Copy link
Contributor

The next step would be to make a PR that:

  1. Adds the native component prop. I might actually recommend a new name instead of inverted, in case anyone accidentally thinks it will invert their ScrollView.
  2. Makes sure VirtualizedList doesn't trigger the new prop, until the native change is rolled out. Then we can have VirtualizedList take advantage of it.

@hannojg
Copy link
Contributor Author

hannojg commented Jun 26, 2023

Hey @NickGerleman,

I will create two PRs now,

  1. One PR with the native change, but a new prop name. Then we can merge it and wait till it's rolled out.
  2. A PR containing the JS fix, which will set the new prop to apply the fix.

I think this way it should be fine right? I think regular react native users won't be affected by the issue that the JS code of react native might get updated before the native code does.

hannojg added a commit to hannojg/react-native that referenced this pull request Jun 26, 2023
hannojg added a commit to hannojg/react-native that referenced this pull request Jun 26, 2023
facebook-github-bot pushed a commit that referenced this pull request Jul 14, 2023
Summary:
This PR is a result of this PR, which got merged but then reverted:

- #37913

We are trying to implement a workaround for #35350, so react-native users on android API 33+ can use `<FlatList inverted={true} />` without running into ANRs.

This is the native part, where we add a new internal prop named `isInvertedVirtualizedList`, which can in a follow up change be used to achieve the final fix as proposed in #37913

However as NickGerleman pointed out, its important that we first ship the native change.

## Changelog:

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->

[ANDROID] [ADDED] - Native part of fixing ANR when having an inverted FlatList on android API 33+

Pull Request resolved: #38071

Test Plan:
- Check the RN tester app and see that scrollview is still working as expected
- Add the `isInvertedVirtualizedList` prop as test to a scrollview and see how the scrollbar will change position.

Reviewed By: rozele

Differential Revision: D47062200

Pulled By: NickGerleman

fbshipit-source-id: d20eebeec757d9aaeced8561f53556bbb4a492e4
juniorklawa pushed a commit to juniorklawa/react-native that referenced this pull request Jul 20, 2023
…book#38071)

Summary:
This PR is a result of this PR, which got merged but then reverted:

- facebook#37913

We are trying to implement a workaround for facebook#35350, so react-native users on android API 33+ can use `<FlatList inverted={true} />` without running into ANRs.

This is the native part, where we add a new internal prop named `isInvertedVirtualizedList`, which can in a follow up change be used to achieve the final fix as proposed in facebook#37913

However as NickGerleman pointed out, its important that we first ship the native change.

## Changelog:

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->

[ANDROID] [ADDED] - Native part of fixing ANR when having an inverted FlatList on android API 33+

Pull Request resolved: facebook#38071

Test Plan:
- Check the RN tester app and see that scrollview is still working as expected
- Add the `isInvertedVirtualizedList` prop as test to a scrollview and see how the scrollbar will change position.

Reviewed By: rozele

Differential Revision: D47062200

Pulled By: NickGerleman

fbshipit-source-id: d20eebeec757d9aaeced8561f53556bbb4a492e4
facebook-github-bot pushed a commit that referenced this pull request Jul 28, 2023
Summary:
This PR is a result of this PR, which got merged but then reverted:

- #37913

We are trying to implement a workaround for #35350, so react-native users on android API 33+ can use `<FlatList inverted={true} />` without running into ANRs.

As explained in the issue, starting from android API 33 there are severe performance issues when using scaleY: -1 on a view, and its child view, which is what we are doing when inverting the ScrollView component (e.g. in FlatList).

This PR adds a workaround. The workaround is to also scale on the X-Axis which causes a different transform matrix to be created, that doesn't cause the ANR (see the issue for details).
However, when doing that the vertical scroll bar will be on the wrong side, thus we switch the position in the native code once we detect that the list is inverted, using the newly added `isInvertedVirtualizedList` prop.

This is a follow up PR to:

- #38071

⚠️ **Note:** [38071](#38071) needs to be merged and shipped first! Only then we can merge this PR.

## Changelog:

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->

[ANDROID] [FIXED] - ANR when having an inverted FlatList on android API 33+

Pull Request resolved: #38073

Test Plan:
- Check the RN tester app and see that scrollview is still working as expected
- Add the `internalAndroidApplyInvertedFix` prop as test to a scrollview and see how the scrollbar will change position.

Reviewed By: cortinico

Differential Revision: D47848063

Pulled By: NickGerleman

fbshipit-source-id: 4a6948a8b89f0b39f01b7a2d44dba740c53fabb3
billnbell pushed a commit to billnbell/react-native that referenced this pull request Jul 29, 2023
Summary:
This PR is a result of this PR, which got merged but then reverted:

- facebook#37913

We are trying to implement a workaround for facebook#35350, so react-native users on android API 33+ can use `<FlatList inverted={true} />` without running into ANRs.

As explained in the issue, starting from android API 33 there are severe performance issues when using scaleY: -1 on a view, and its child view, which is what we are doing when inverting the ScrollView component (e.g. in FlatList).

This PR adds a workaround. The workaround is to also scale on the X-Axis which causes a different transform matrix to be created, that doesn't cause the ANR (see the issue for details).
However, when doing that the vertical scroll bar will be on the wrong side, thus we switch the position in the native code once we detect that the list is inverted, using the newly added `isInvertedVirtualizedList` prop.

This is a follow up PR to:

- facebook#38071

⚠️ **Note:** [38071](facebook#38071) needs to be merged and shipped first! Only then we can merge this PR.

## Changelog:

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->

[ANDROID] [FIXED] - ANR when having an inverted FlatList on android API 33+

Pull Request resolved: facebook#38073

Test Plan:
- Check the RN tester app and see that scrollview is still working as expected
- Add the `internalAndroidApplyInvertedFix` prop as test to a scrollview and see how the scrollbar will change position.

Reviewed By: cortinico

Differential Revision: D47848063

Pulled By: NickGerleman

fbshipit-source-id: 4a6948a8b89f0b39f01b7a2d44dba740c53fabb3
billnbell pushed a commit to billnbell/react-native that referenced this pull request Jul 29, 2023
Summary:
This PR is a result of this PR, which got merged but then reverted:

- facebook#37913

We are trying to implement a workaround for facebook#35350, so react-native users on android API 33+ can use `<FlatList inverted={true} />` without running into ANRs.

As explained in the issue, starting from android API 33 there are severe performance issues when using scaleY: -1 on a view, and its child view, which is what we are doing when inverting the ScrollView component (e.g. in FlatList).

This PR adds a workaround. The workaround is to also scale on the X-Axis which causes a different transform matrix to be created, that doesn't cause the ANR (see the issue for details).
However, when doing that the vertical scroll bar will be on the wrong side, thus we switch the position in the native code once we detect that the list is inverted, using the newly added `isInvertedVirtualizedList` prop.

This is a follow up PR to:

- facebook#38071

⚠️ **Note:** [38071](facebook#38071) needs to be merged and shipped first! Only then we can merge this PR.

## Changelog:

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->

[ANDROID] [FIXED] - ANR when having an inverted FlatList on android API 33+

Pull Request resolved: facebook#38073

Test Plan:
- Check the RN tester app and see that scrollview is still working as expected
- Add the `internalAndroidApplyInvertedFix` prop as test to a scrollview and see how the scrollbar will change position.

Reviewed By: cortinico

Differential Revision: D47848063

Pulled By: NickGerleman

fbshipit-source-id: 4a6948a8b89f0b39f01b7a2d44dba740c53fabb3
billnbell pushed a commit to billnbell/react-native that referenced this pull request Jul 29, 2023
Summary:
This PR is a result of this PR, which got merged but then reverted:

- facebook#37913

We are trying to implement a workaround for facebook#35350, so react-native users on android API 33+ can use `<FlatList inverted={true} />` without running into ANRs.

As explained in the issue, starting from android API 33 there are severe performance issues when using scaleY: -1 on a view, and its child view, which is what we are doing when inverting the ScrollView component (e.g. in FlatList).

This PR adds a workaround. The workaround is to also scale on the X-Axis which causes a different transform matrix to be created, that doesn't cause the ANR (see the issue for details).
However, when doing that the vertical scroll bar will be on the wrong side, thus we switch the position in the native code once we detect that the list is inverted, using the newly added `isInvertedVirtualizedList` prop.

This is a follow up PR to:

- facebook#38071

⚠️ **Note:** [38071](facebook#38071) needs to be merged and shipped first! Only then we can merge this PR.

## Changelog:

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->

[ANDROID] [FIXED] - ANR when having an inverted FlatList on android API 33+

Pull Request resolved: facebook#38073

Test Plan:
- Check the RN tester app and see that scrollview is still working as expected
- Add the `internalAndroidApplyInvertedFix` prop as test to a scrollview and see how the scrollbar will change position.

Reviewed By: cortinico

Differential Revision: D47848063

Pulled By: NickGerleman

fbshipit-source-id: 4a6948a8b89f0b39f01b7a2d44dba740c53fabb3
zhxlp added a commit to zhxlp/react-native that referenced this pull request Aug 1, 2023
…book#38071)

Summary:
This PR is a result of this PR, which got merged but then reverted:

- facebook#37913

We are trying to implement a workaround for facebook#35350, so react-native users on android API 33+ can use <FlatList inverted={true} /> without running into ANRs.

This is the native part, where we add a new internal prop named isInvertedVirtualizedList, which can in a follow up change be used to achieve the final fix as proposed in facebook#37913

However as NickGerleman pointed out, its important that we first ship the native change.

## Changelog:

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->

[ANDROID] [ADDED] - Native part of fixing ANR when having an inverted FlatList on android API 33+

Pull Request resolved: facebook#38071

Test Plan:
- Check the RN tester app and see that scrollview is still working as expected
- Add the isInvertedVirtualizedList prop as test to a scrollview and see how the scrollbar will change position.

Reviewed By: rozele

Differential Revision: D47062200

Pulled By: NickGerleman

fbshipit-source-id: d20eebeec757d9aaeced8561f53556bbb4a492e4
lunaleaps pushed a commit that referenced this pull request Aug 7, 2023
Summary:
This PR is a result of this PR, which got merged but then reverted:

- #37913

We are trying to implement a workaround for #35350, so react-native users on android API 33+ can use `<FlatList inverted={true} />` without running into ANRs.

This is the native part, where we add a new internal prop named `isInvertedVirtualizedList`, which can in a follow up change be used to achieve the final fix as proposed in #37913

However as NickGerleman pointed out, its important that we first ship the native change.

## Changelog:

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->

[ANDROID] [ADDED] - Native part of fixing ANR when having an inverted FlatList on android API 33+

Pull Request resolved: #38071

Test Plan:
- Check the RN tester app and see that scrollview is still working as expected
- Add the `isInvertedVirtualizedList` prop as test to a scrollview and see how the scrollbar will change position.

Reviewed By: rozele

Differential Revision: D47062200

Pulled By: NickGerleman

fbshipit-source-id: d20eebeec757d9aaeced8561f53556bbb4a492e4
lunaleaps pushed a commit that referenced this pull request Aug 7, 2023
Summary:
This PR is a result of this PR, which got merged but then reverted:

- #37913

We are trying to implement a workaround for #35350, so react-native users on android API 33+ can use `<FlatList inverted={true} />` without running into ANRs.

As explained in the issue, starting from android API 33 there are severe performance issues when using scaleY: -1 on a view, and its child view, which is what we are doing when inverting the ScrollView component (e.g. in FlatList).

This PR adds a workaround. The workaround is to also scale on the X-Axis which causes a different transform matrix to be created, that doesn't cause the ANR (see the issue for details).
However, when doing that the vertical scroll bar will be on the wrong side, thus we switch the position in the native code once we detect that the list is inverted, using the newly added `isInvertedVirtualizedList` prop.

This is a follow up PR to:

- #38071

⚠️ **Note:** [38071](#38071) needs to be merged and shipped first! Only then we can merge this PR.

## Changelog:

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->

[ANDROID] [FIXED] - ANR when having an inverted FlatList on android API 33+

Pull Request resolved: #38073

Test Plan:
- Check the RN tester app and see that scrollview is still working as expected
- Add the `internalAndroidApplyInvertedFix` prop as test to a scrollview and see how the scrollbar will change position.

Reviewed By: cortinico

Differential Revision: D47848063

Pulled By: NickGerleman

fbshipit-source-id: 4a6948a8b89f0b39f01b7a2d44dba740c53fabb3
Kudo pushed a commit to expo/react-native that referenced this pull request Aug 21, 2023
…book#38071)

Summary:
This PR is a result of this PR, which got merged but then reverted:

- facebook#37913

We are trying to implement a workaround for facebook#35350, so react-native users on android API 33+ can use `<FlatList inverted={true} />` without running into ANRs.

This is the native part, where we add a new internal prop named `isInvertedVirtualizedList`, which can in a follow up change be used to achieve the final fix as proposed in facebook#37913

However as NickGerleman pointed out, its important that we first ship the native change.

## Changelog:

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->

[ANDROID] [ADDED] - Native part of fixing ANR when having an inverted FlatList on android API 33+

Pull Request resolved: facebook#38071

Test Plan:
- Check the RN tester app and see that scrollview is still working as expected
- Add the `isInvertedVirtualizedList` prop as test to a scrollview and see how the scrollbar will change position.

Reviewed By: rozele

Differential Revision: D47062200

Pulled By: NickGerleman

fbshipit-source-id: d20eebeec757d9aaeced8561f53556bbb4a492e4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Merged This PR has been merged. Reverted
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants