Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<b66656cc0c4c1556986bcb765b1a4717>>
* @generated SignedSource<<cd8b6b6fdb11377c119f6bb979560b0e>>
*/

/**
Expand Down Expand Up @@ -280,6 +280,12 @@ public object ReactNativeFeatureFlags {
@JvmStatic
public fun useOptimisedViewPreallocationOnAndroid(): Boolean = accessor.useOptimisedViewPreallocationOnAndroid()

/**
* Uses an optimized mechanism for event batching on Android that does not need to wait for a Choreographer frame callback.
*/
@JvmStatic
public fun useOptimizedEventBatchingOnAndroid(): Boolean = accessor.useOptimizedEventBatchingOnAndroid()

/**
* When enabled, cloning shadow nodes within react native will update the reference held by the current JS fiber tree.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<ffc9e4785820aa65fad28f79d27a85d2>>
* @generated SignedSource<<47dbdb6ffcd04bb7b2d2d01c4c1e7ace>>
*/

/**
Expand Down Expand Up @@ -62,6 +62,7 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso
private var useNativeViewConfigsInBridgelessModeCache: Boolean? = null
private var useNewReactImageViewBackgroundDrawingCache: Boolean? = null
private var useOptimisedViewPreallocationOnAndroidCache: Boolean? = null
private var useOptimizedEventBatchingOnAndroidCache: Boolean? = null
private var useRuntimeShadowNodeReferenceUpdateCache: Boolean? = null
private var useRuntimeShadowNodeReferenceUpdateOnLayoutCache: Boolean? = null
private var useStateAlignmentMechanismCache: Boolean? = null
Expand Down Expand Up @@ -445,6 +446,15 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso
return cached
}

override fun useOptimizedEventBatchingOnAndroid(): Boolean {
var cached = useOptimizedEventBatchingOnAndroidCache
if (cached == null) {
cached = ReactNativeFeatureFlagsCxxInterop.useOptimizedEventBatchingOnAndroid()
useOptimizedEventBatchingOnAndroidCache = cached
}
return cached
}

override fun useRuntimeShadowNodeReferenceUpdate(): Boolean {
var cached = useRuntimeShadowNodeReferenceUpdateCache
if (cached == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<580db8acae42a65aeb678d2d6ef4630c>>
* @generated SignedSource<<93ce8e0026e125192af1ad86730941c0>>
*/

/**
Expand Down Expand Up @@ -112,6 +112,8 @@ public object ReactNativeFeatureFlagsCxxInterop {

@DoNotStrip @JvmStatic public external fun useOptimisedViewPreallocationOnAndroid(): Boolean

@DoNotStrip @JvmStatic public external fun useOptimizedEventBatchingOnAndroid(): Boolean

@DoNotStrip @JvmStatic public external fun useRuntimeShadowNodeReferenceUpdate(): Boolean

@DoNotStrip @JvmStatic public external fun useRuntimeShadowNodeReferenceUpdateOnLayout(): Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<00aae631e9d9b146fae9be838e04e165>>
* @generated SignedSource<<be36697a6f863c364f858112767399f8>>
*/

/**
Expand Down Expand Up @@ -107,6 +107,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi

override fun useOptimisedViewPreallocationOnAndroid(): Boolean = false

override fun useOptimizedEventBatchingOnAndroid(): Boolean = false

override fun useRuntimeShadowNodeReferenceUpdate(): Boolean = false

override fun useRuntimeShadowNodeReferenceUpdateOnLayout(): Boolean = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<ead344838f30d7e3f1205d7bbabbc803>>
* @generated SignedSource<<7727737ae31a239d6b68397fafadbfea>>
*/

/**
Expand Down Expand Up @@ -66,6 +66,7 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces
private var useNativeViewConfigsInBridgelessModeCache: Boolean? = null
private var useNewReactImageViewBackgroundDrawingCache: Boolean? = null
private var useOptimisedViewPreallocationOnAndroidCache: Boolean? = null
private var useOptimizedEventBatchingOnAndroidCache: Boolean? = null
private var useRuntimeShadowNodeReferenceUpdateCache: Boolean? = null
private var useRuntimeShadowNodeReferenceUpdateOnLayoutCache: Boolean? = null
private var useStateAlignmentMechanismCache: Boolean? = null
Expand Down Expand Up @@ -491,6 +492,16 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces
return cached
}

override fun useOptimizedEventBatchingOnAndroid(): Boolean {
var cached = useOptimizedEventBatchingOnAndroidCache
if (cached == null) {
cached = currentProvider.useOptimizedEventBatchingOnAndroid()
accessedFeatureFlags.add("useOptimizedEventBatchingOnAndroid")
useOptimizedEventBatchingOnAndroidCache = cached
}
return cached
}

override fun useRuntimeShadowNodeReferenceUpdate(): Boolean {
var cached = useRuntimeShadowNodeReferenceUpdateCache
if (cached == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<2c8c28515aa6929b975ef7193c8bf72e>>
* @generated SignedSource<<d9975558a8a9981b4f43e7c5d4473231>>
*/

/**
Expand Down Expand Up @@ -107,6 +107,8 @@ public interface ReactNativeFeatureFlagsProvider {

@DoNotStrip public fun useOptimisedViewPreallocationOnAndroid(): Boolean

@DoNotStrip public fun useOptimizedEventBatchingOnAndroid(): Boolean

@DoNotStrip public fun useRuntimeShadowNodeReferenceUpdate(): Boolean

@DoNotStrip public fun useRuntimeShadowNodeReferenceUpdateOnLayout(): Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

package com.facebook.react.uimanager.events;

import android.os.Handler;
import android.view.Choreographer;
import com.facebook.infer.annotation.Nullsafe;
import com.facebook.react.bridge.LifecycleEventListener;
Expand All @@ -15,6 +16,7 @@
import com.facebook.react.bridge.ReactSoftExceptionLogger;
import com.facebook.react.bridge.UIManager;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags;
import com.facebook.react.modules.core.ReactChoreographer;
import com.facebook.react.uimanager.UIManagerHelper;
import com.facebook.react.uimanager.common.UIManagerType;
Expand All @@ -27,6 +29,8 @@
*/
@Nullsafe(Nullsafe.Mode.LOCAL)
public class FabricEventDispatcher implements EventDispatcher, LifecycleEventListener {
private static final Handler uiThreadHandler = UiThreadUtil.getUiThreadHandler();

private final ReactEventEmitter mReactEventEmitter;
private final ReactApplicationContext mReactContext;
private final CopyOnWriteArrayList<EventDispatcherListener> mListeners =
Expand All @@ -36,6 +40,25 @@ public class FabricEventDispatcher implements EventDispatcher, LifecycleEventLis
private final FabricEventDispatcher.ScheduleDispatchFrameCallback mCurrentFrameCallback =
new FabricEventDispatcher.ScheduleDispatchFrameCallback();

private boolean mIsDispatchScheduled = false;
private final Runnable mDispatchEventsRunnable =
new Runnable() {
@Override
public void run() {
mIsDispatchScheduled = false;

Systrace.beginSection(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "BatchEventDispatchedListeners");
try {
for (BatchEventDispatchedListener listener : mPostEventDispatchListeners) {
listener.onBatchEventDispatched();
}
} finally {
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
}
}
};

public FabricEventDispatcher(ReactApplicationContext reactContext) {
mReactContext = reactContext;
mReactContext.addLifecycleEventListener(this);
Expand All @@ -54,7 +77,7 @@ public void dispatchEvent(Event event) {
}

event.dispose();
maybePostFrameCallbackFromNonUI();
scheduleDispatchOfBatchedEvents();
}

private void dispatchSynchronous(Event event) {
Expand Down Expand Up @@ -85,19 +108,17 @@ private void dispatchSynchronous(Event event) {
}

public void dispatchAllEvents() {
maybePostFrameCallbackFromNonUI();
scheduleDispatchOfBatchedEvents();
}

private void maybePostFrameCallbackFromNonUI() {
if (mReactEventEmitter != null) {
// If the host activity is paused, the frame callback may not be currently
// posted. Ensure that it is so that this event gets delivered promptly.
mCurrentFrameCallback.maybePostFromNonUI();
private void scheduleDispatchOfBatchedEvents() {
if (ReactNativeFeatureFlags.useOptimizedEventBatchingOnAndroid()) {
if (!mIsDispatchScheduled) {
mIsDispatchScheduled = true;
uiThreadHandler.postAtFrontOfQueue(mDispatchEventsRunnable);
}
} else {
// No JS application has started yet, or resumed. This can happen when a ReactRootView is
// added to view hierarchy, but ReactContext creation has not completed yet. In this case, any
// touch event dispatch will hit this codepath, and we simply queue them so that they
// are dispatched once ReactContext creation completes and JS app is running.
mCurrentFrameCallback.maybeScheduleDispatchOfBatchedEvents();
}
}

Expand All @@ -121,32 +142,37 @@ public void removeBatchEventDispatchedListener(BatchEventDispatchedListener list

@Override
public void onHostResume() {
maybePostFrameCallbackFromNonUI();
scheduleDispatchOfBatchedEvents();
}

@Override
public void onHostPause() {
stopFrameCallback();
cancelDispatchOfBatchedEvents();
}

@Override
public void onHostDestroy() {
stopFrameCallback();
cancelDispatchOfBatchedEvents();
}

public void onCatalystInstanceDestroyed() {
UiThreadUtil.runOnUiThread(
new Runnable() {
@Override
public void run() {
stopFrameCallback();
cancelDispatchOfBatchedEvents();
}
});
}

private void stopFrameCallback() {
private void cancelDispatchOfBatchedEvents() {
UiThreadUtil.assertOnUiThread();
mCurrentFrameCallback.stop();
if (ReactNativeFeatureFlags.useOptimizedEventBatchingOnAndroid()) {
mIsDispatchScheduled = false;
uiThreadHandler.removeCallbacks(mDispatchEventsRunnable);
} else {
mCurrentFrameCallback.stop();
}
}

public void registerEventEmitter(@UIManagerType int uiManagerType, RCTEventEmitter eventEmitter) {
Expand All @@ -163,17 +189,17 @@ public void unregisterEventEmitter(@UIManagerType int uiManagerType) {
}

private class ScheduleDispatchFrameCallback implements Choreographer.FrameCallback {
private volatile boolean mIsPosted = false;
private volatile boolean mIsDispatchScheduled = false;
private boolean mShouldStop = false;

@Override
public void doFrame(long frameTimeNanos) {
UiThreadUtil.assertOnUiThread();

if (mShouldStop) {
mIsPosted = false;
mIsDispatchScheduled = false;
} else {
post();
dispatchBatchedEvents();
}

Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "BatchEventDispatchedListeners");
Expand All @@ -190,32 +216,32 @@ public void stop() {
mShouldStop = true;
}

public void maybePost() {
if (!mIsPosted) {
mIsPosted = true;
post();
public void maybeDispatchBatchedEvents() {
if (!mIsDispatchScheduled) {
mIsDispatchScheduled = true;
dispatchBatchedEvents();
}
}

private void post() {
private void dispatchBatchedEvents() {
ReactChoreographer.getInstance()
.postFrameCallback(ReactChoreographer.CallbackType.TIMERS_EVENTS, mCurrentFrameCallback);
}

public void maybePostFromNonUI() {
if (mIsPosted) {
public void maybeScheduleDispatchOfBatchedEvents() {
if (mIsDispatchScheduled) {
return;
}

// We should only hit this slow path when we receive events while the host activity is paused.
if (mReactContext.isOnUiQueueThread()) {
maybePost();
maybeDispatchBatchedEvents();
} else {
mReactContext.runOnUiQueueThread(
new Runnable() {
@Override
public void run() {
maybePost();
maybeDispatchBatchedEvents();
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<35f5003b77104e68e32741e4626e2ba6>>
* @generated SignedSource<<c01d216f03d56fed027117e78dc590ab>>
*/

/**
Expand Down Expand Up @@ -291,6 +291,12 @@ class ReactNativeFeatureFlagsProviderHolder
return method(javaProvider_);
}

bool useOptimizedEventBatchingOnAndroid() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("useOptimizedEventBatchingOnAndroid");
return method(javaProvider_);
}

bool useRuntimeShadowNodeReferenceUpdate() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("useRuntimeShadowNodeReferenceUpdate");
Expand Down Expand Up @@ -529,6 +535,11 @@ bool JReactNativeFeatureFlagsCxxInterop::useOptimisedViewPreallocationOnAndroid(
return ReactNativeFeatureFlags::useOptimisedViewPreallocationOnAndroid();
}

bool JReactNativeFeatureFlagsCxxInterop::useOptimizedEventBatchingOnAndroid(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::useOptimizedEventBatchingOnAndroid();
}

bool JReactNativeFeatureFlagsCxxInterop::useRuntimeShadowNodeReferenceUpdate(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::useRuntimeShadowNodeReferenceUpdate();
Expand Down Expand Up @@ -692,6 +703,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
makeNativeMethod(
"useOptimisedViewPreallocationOnAndroid",
JReactNativeFeatureFlagsCxxInterop::useOptimisedViewPreallocationOnAndroid),
makeNativeMethod(
"useOptimizedEventBatchingOnAndroid",
JReactNativeFeatureFlagsCxxInterop::useOptimizedEventBatchingOnAndroid),
makeNativeMethod(
"useRuntimeShadowNodeReferenceUpdate",
JReactNativeFeatureFlagsCxxInterop::useRuntimeShadowNodeReferenceUpdate),
Expand Down
Loading