From b9396cd74419dd4165fb051605076d19b1c18905 Mon Sep 17 00:00:00 2001 From: Andy Street Date: Thu, 7 Apr 2016 13:10:56 -0700 Subject: [PATCH] Synchronize ProgressBar constructors Summary: If a ProgressBar is created on the shadow thread (for measurement) at the same time one is created on the UI thread, we hit a race condition which sometimes results in a crash (##java.lang.NullPointerException: Null pointer exception during instruction 'invoke-static {v5}, android.animation.AnimatorSet$Node android.animation.AnimatorSet$Node.access$200(android.animation.AnimatorSet$Node) // method@153'##). This diff synchronizes the ctors. Reviewed By: foghina Differential Revision: D3151037 fb-gh-sync-id: 8ed96d6debdc1a5fa2f9bd037bfb75def25be3e8 fbshipit-source-id: 8ed96d6debdc1a5fa2f9bd037bfb75def25be3e8 --- .../progressbar/ProgressBarContainerView.java | 2 +- .../views/progressbar/ProgressBarShadowNode.java | 2 +- .../progressbar/ReactProgressBarViewManager.java | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarContainerView.java b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarContainerView.java index 233981506..d71b66922 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarContainerView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarContainerView.java @@ -31,7 +31,7 @@ import com.facebook.react.bridge.JSApplicationIllegalArgumentException; public void setStyle(@Nullable String styleName) { int style = ReactProgressBarViewManager.getStyleFromString(styleName); - mProgressBar = new ProgressBar(getContext(), null, style); + mProgressBar = ReactProgressBarViewManager.createProgressBar(getContext(), style); mProgressBar.setMax(MAX_PROGRESS); removeAllViews(); addView( diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java index ee272724b..ce85293fb 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java @@ -61,7 +61,7 @@ public class ProgressBarShadowNode extends LayoutShadowNode implements CSSNode.M MeasureOutput measureOutput) { final int style = ReactProgressBarViewManager.getStyleFromString(getStyle()); if (!mMeasured.contains(style)) { - ProgressBar progressBar = new ProgressBar(getThemedContext(), null, style); + ProgressBar progressBar = ReactProgressBarViewManager.createProgressBar(getThemedContext(), style); final int spec = View.MeasureSpec.makeMeasureSpec( ViewGroup.LayoutParams.WRAP_CONTENT, View.MeasureSpec.UNSPECIFIED); diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ReactProgressBarViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ReactProgressBarViewManager.java index 82601cedd..38454282e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ReactProgressBarViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ReactProgressBarViewManager.java @@ -11,6 +11,9 @@ package com.facebook.react.views.progressbar; import javax.annotation.Nullable; +import android.content.Context; +import android.widget.ProgressBar; + import com.facebook.react.bridge.JSApplicationIllegalArgumentException; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.annotations.ReactProp; @@ -33,6 +36,19 @@ public class ReactProgressBarViewManager extends /* package */ static final String REACT_CLASS = "AndroidProgressBar"; /* package */ static final String DEFAULT_STYLE = "Normal"; + private static Object sProgressBarCtorLock = new Object(); + + /** + * We create ProgressBars on both the UI and shadow threads. There is a race condition in the + * ProgressBar constructor that may cause crashes when two ProgressBars are constructed at the + * same time on two different threads. This static ctor wrapper protects against that. + */ + public static ProgressBar createProgressBar(Context context, int style) { + synchronized (sProgressBarCtorLock) { + return new ProgressBar(context, null, style); + } + } + @Override public String getName() { return REACT_CLASS;