Allow horizontal scroll view also retry side-effects when content view is not mounted

Summary:
This diff fixed a NPE in horizontal scroll view when calling scrollToEnd API in side effect.

The problem here is we may trigger side-effects before the required view got mounted for performance reasons. We've been fixing this with retry logic on those side-effects and we've already done this in vertical scroll view. This is to fix on the horizontal scroll as well.

Changelog:
[Android][Fixed] - Fixed HorizontalScrollView API scrollToEnd causing NPE in side-effects.

Reviewed By: lunaleaps, JoshuaGross

Differential Revision: D37571847

fbshipit-source-id: 0a4dc38381008350fd09908aa3ebb64e3e65a424
This commit is contained in:
Xin Chen
2022-07-06 12:18:37 -07:00
committed by Facebook GitHub Bot
parent ec3c8f4380
commit e5ba6ab7b4
2 changed files with 14 additions and 2 deletions
@@ -8,10 +8,12 @@
package com.facebook.react.views.scroll;
import android.graphics.Color;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.core.view.ViewCompat;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.RetryableMountingLayerException;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.PointerEvents;
@@ -208,8 +210,15 @@ public class ReactHorizontalScrollViewManager extends ViewGroupManager<ReactHori
public void scrollToEnd(
ReactHorizontalScrollView scrollView,
ReactScrollViewCommandHelper.ScrollToEndCommandData data) {
// ScrollView always has one child - the scrollable area
int right = scrollView.getChildAt(0).getWidth() + scrollView.getPaddingRight();
// ScrollView always has one child - the scrollable area. However, it's possible today that we
// execute this method as view command before the child view is mounted. Here we will retry the
// view commands as a workaround.
@Nullable View child = scrollView.getChildAt(0);
if (child == null) {
throw new RetryableMountingLayerException(
"scrollToEnd called on HorizontalScrollView without child");
}
int right = child.getWidth() + scrollView.getPaddingRight();
if (data.mAnimated) {
scrollView.reactSmoothScrollTo(right, scrollView.getScrollY());
} else {
@@ -285,6 +285,9 @@ public class ReactScrollViewManager extends ViewGroupManager<ReactScrollView>
@Override
public void scrollToEnd(
ReactScrollView scrollView, ReactScrollViewCommandHelper.ScrollToEndCommandData data) {
// ScrollView always has one child - the scrollable area. However, it's possible today that we
// execute this method as view command before the child view is mounted. Here we will retry the
// view commands as a workaround.
View child = scrollView.getChildAt(0);
if (child == null) {
throw new RetryableMountingLayerException("scrollToEnd called on ScrollView without child");