diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java index 6250d2414..13a38acd0 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java @@ -31,6 +31,7 @@ import com.facebook.react.cxxbridge.CatalystInstanceImpl; import com.facebook.react.cxxbridge.JSBundleLoader; import com.facebook.react.cxxbridge.JSCJavaScriptExecutor; import com.facebook.react.cxxbridge.JavaScriptExecutor; +import com.facebook.react.modules.core.ReactChoreographer; import com.android.internal.util.Predicate; @@ -153,6 +154,7 @@ public class ReactTestHelper { InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { @Override public void run() { + ReactChoreographer.initialize(); instance.initialize(); } }); diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index 97f6f5142..cce649946 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -61,6 +61,7 @@ import com.facebook.react.devsupport.interfaces.PackagerStatusCallback; import com.facebook.react.modules.appregistry.AppRegistry; import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; import com.facebook.react.modules.core.DeviceEventManagerModule; +import com.facebook.react.modules.core.ReactChoreographer; import com.facebook.react.modules.debug.interfaces.DeveloperSettings; import com.facebook.react.uimanager.DisplayMetricsHolder; import com.facebook.react.uimanager.UIImplementationProvider; @@ -348,6 +349,9 @@ public class ReactInstanceManager { mLazyNativeModulesEnabled = lazyNativeModulesEnabled; mLazyViewManagersEnabled = lazyViewManagersEnabled; mUseStartupThread = useStartupThread; + + // Instantiate ReactChoreographer in UI thread. + ReactChoreographer.initialize(); } public DevSupportManager getDevSupportManager() { diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/core/ReactChoreographer.java b/ReactAndroid/src/main/java/com/facebook/react/modules/core/ReactChoreographer.java index 71aecde75..4e622f524 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/core/ReactChoreographer.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/core/ReactChoreographer.java @@ -12,8 +12,8 @@ package com.facebook.react.modules.core; import java.util.ArrayDeque; import com.facebook.common.logging.FLog; -import com.facebook.react.bridge.UiThreadUtil; import com.facebook.infer.annotation.Assertions; +import com.facebook.react.bridge.UiThreadUtil; import com.facebook.react.common.ReactConstants; /** @@ -65,11 +65,15 @@ public class ReactChoreographer { private static ReactChoreographer sInstance; - public static ReactChoreographer getInstance() { - UiThreadUtil.assertOnUiThread(); + public static void initialize() { if (sInstance == null) { + UiThreadUtil.assertOnUiThread(); sInstance = new ReactChoreographer(); } + } + + public static ReactChoreographer getInstance() { + Assertions.assertNotNull(sInstance, "ReactChoreographer needs to be initialized."); return sInstance; } @@ -89,8 +93,9 @@ public class ReactChoreographer { } } - public void postFrameCallback(CallbackType type, ChoreographerCompat.FrameCallback frameCallback) { - UiThreadUtil.assertOnUiThread(); + public synchronized void postFrameCallback( + CallbackType type, + ChoreographerCompat.FrameCallback frameCallback) { mCallbackQueues[type.getOrder()].addLast(frameCallback); mTotalCallbacks++; Assertions.assertCondition(mTotalCallbacks > 0); @@ -100,8 +105,9 @@ public class ReactChoreographer { } } - public void removeFrameCallback(CallbackType type, ChoreographerCompat.FrameCallback frameCallback) { - UiThreadUtil.assertOnUiThread(); + public synchronized void removeFrameCallback( + CallbackType type, + ChoreographerCompat.FrameCallback frameCallback) { if (mCallbackQueues[type.getOrder()].removeFirstOccurrence(frameCallback)) { mTotalCallbacks--; maybeRemoveFrameCallback(); @@ -122,15 +128,17 @@ public class ReactChoreographer { @Override public void doFrame(long frameTimeNanos) { - mHasPostedCallback = false; - for (int i = 0; i < mCallbackQueues.length; i++) { - int initialLength = mCallbackQueues[i].size(); - for (int callback = 0; callback < initialLength; callback++) { - mCallbackQueues[i].removeFirst().doFrame(frameTimeNanos); - mTotalCallbacks--; + synchronized (ReactChoreographer.this) { + mHasPostedCallback = false; + for (int i = 0; i < mCallbackQueues.length; i++) { + int initialLength = mCallbackQueues[i].size(); + for (int callback = 0; callback < initialLength; callback++) { + mCallbackQueues[i].removeFirst().doFrame(frameTimeNanos); + mTotalCallbacks--; + } } + maybeRemoveFrameCallback(); } - maybeRemoveFrameCallback(); } } }