Create V2 EventEmitter (ModernEventEmitter) interface that surfaceId can be passed into

Summary:
Create V2 EventEmitter that surfaceId can be passed into, with a backwards-compat layer, and some debug-only logging to help assist with migration.

Changelog: [Changed][Android] RCTEventEmitter has been deprecated in favor of RCTModernEventEmitter for optimal Fabric support; RCTEventEmitter will continue to work in Fabric, but there are minor perf implications.

Reviewed By: mdvacca

Differential Revision: D26027104

fbshipit-source-id: 784ca092bbc88d19c82f6c42537c34460d96de86
This commit is contained in:
Joshua Gross
2021-01-22 19:29:00 -08:00
committed by Facebook GitHub Bot
parent 8357b39908
commit 2fbbdbb2ce
8 changed files with 111 additions and 11 deletions
@@ -125,8 +125,20 @@ public interface UIManager extends JSIModule, PerformanceCounter {
* @param eventName name of the event
* @param event parameters
*/
@Deprecated
void receiveEvent(int reactTag, String eventName, @Nullable WritableMap event);
/**
* This method dispatches events from RN Android code to JS. The delivery of this event will not
* be queued in EventDispatcher class.
*
* @param surfaceId
* @param reactTag tag
* @param eventName name of the event
* @param event parameters
*/
void receiveEvent(int surfaceId, int reactTag, String eventName, @Nullable WritableMap event);
/** Resolves Direct Event name exposed to JS from the one known to the Native side. */
@Deprecated
@Nullable
@@ -53,6 +53,7 @@ import com.facebook.react.bridge.UIManager;
import com.facebook.react.bridge.UIManagerListener;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.common.build.ReactBuildConfig;
import com.facebook.react.config.ReactFeatureFlags;
import com.facebook.react.fabric.events.EventBeatManager;
import com.facebook.react.fabric.events.EventEmitterWrapper;
@@ -90,8 +91,8 @@ import java.util.concurrent.CopyOnWriteArrayList;
@SuppressLint("MissingNativeLoadLibrary")
public class FabricUIManager implements UIManager, LifecycleEventListener {
public static final String TAG = FabricUIManager.class.getSimpleName();
public static final String TAG = "FabricUIManager";
// The IS_DEVELOPMENT_ENVIRONMENT variable is used to log extra data when running fabric in a
// development environment. DO NOT ENABLE THIS ON PRODUCTION OR YOU WILL BE FIRED!
public static final boolean IS_DEVELOPMENT_ENVIRONMENT = false;
@@ -895,7 +896,18 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
@Override
public void receiveEvent(int reactTag, String eventName, @Nullable WritableMap params) {
EventEmitterWrapper eventEmitter = mMountingManager.getEventEmitter(reactTag);
receiveEvent(-1, reactTag, eventName, params);
}
@Override
public void receiveEvent(
int surfaceId, int reactTag, String eventName, @Nullable WritableMap params) {
if (ReactBuildConfig.DEBUG && surfaceId == -1) {
FLog.d(TAG, "Emitted event without surfaceId: [%d] %s", reactTag, eventName);
}
EventEmitterWrapper eventEmitter = mMountingManager.getEventEmitter(surfaceId, reactTag);
if (eventEmitter == null) {
// This can happen if the view has disappeared from the screen (because of async events)
FLog.d(TAG, "Unable to invoke event: " + eventName + " for reactTag: " + reactTag);
@@ -23,12 +23,12 @@ import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeArray;
import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.fabric.FabricUIManager;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import com.facebook.react.uimanager.events.RCTModernEventEmitter;
import com.facebook.systrace.Systrace;
import java.util.HashSet;
import java.util.Set;
public class FabricEventEmitter implements RCTEventEmitter {
public class FabricEventEmitter implements RCTModernEventEmitter {
private static final String TAG = "FabricEventEmitter";
@@ -40,10 +40,16 @@ public class FabricEventEmitter implements RCTEventEmitter {
@Override
public void receiveEvent(int reactTag, @NonNull String eventName, @Nullable WritableMap params) {
receiveEvent(-1, reactTag, eventName, params);
}
@Override
public void receiveEvent(
int surfaceId, int reactTag, String eventName, @Nullable WritableMap params) {
Systrace.beginSection(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
"FabricEventEmitter.receiveEvent('" + eventName + "')");
mUIManager.receiveEvent(reactTag, eventName, params);
mUIManager.receiveEvent(surfaceId, reactTag, eventName, params);
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
}
@@ -311,8 +311,9 @@ public class MountingManager {
@AnyThread
@ThreadConfined(ANY)
public @Nullable EventEmitterWrapper getEventEmitter(int reactTag) {
SurfaceMountingManager surfaceMountingManager = getSurfaceManagerForView(reactTag);
public @Nullable EventEmitterWrapper getEventEmitter(int surfaceId, int reactTag) {
SurfaceMountingManager surfaceMountingManager =
(surfaceId == -1 ? getSurfaceManagerForView(reactTag) : getSurfaceManager(surfaceId));
if (surfaceMountingManager == null) {
return null;
}
@@ -87,6 +87,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
@ReactModule(name = UIManagerModule.NAME)
public class UIManagerModule extends ReactContextBaseJavaModule
implements OnBatchCompleteListener, LifecycleEventListener, UIManager {
public static final String TAG = UIManagerModule.class.getSimpleName();
/** Enables lazy discovery of a specific {@link ViewManager} by its name. */
public interface ViewManagerResolver {
@@ -993,9 +994,16 @@ public class UIManagerModule extends ReactContextBaseJavaModule
}
@Override
public void receiveEvent(int targetTag, String eventName, @Nullable WritableMap event) {
public void receiveEvent(int reactTag, String eventName, @Nullable WritableMap event) {
receiveEvent(-1, reactTag, eventName, event);
}
@Override
public void receiveEvent(
int surfaceId, int reactTag, String eventName, @Nullable WritableMap event) {
assert ViewUtil.getUIManagerType(reactTag) == DEFAULT;
getReactApplicationContext()
.getJSModule(RCTEventEmitter.class)
.receiveEvent(targetTag, eventName, event);
.receiveEvent(reactTag, eventName, event);
}
}
@@ -21,18 +21,30 @@ public abstract class Event<T extends Event> {
private static int sUniqueID = 0;
private boolean mInitialized;
private int mSurfaceId;
private int mViewTag;
private long mTimestampMs;
private int mUniqueID = sUniqueID++;
protected Event() {}
@Deprecated
protected Event(int viewTag) {
init(viewTag);
}
/** This method needs to be called before event is sent to event dispatcher. */
protected Event(int surfaceId, int viewTag) {
init(surfaceId, viewTag);
}
@Deprecated
protected void init(int viewTag) {
init(-1, viewTag);
}
/** This method needs to be called before event is sent to event dispatcher. */
protected void init(int surfaceId, int viewTag) {
mSurfaceId = surfaceId;
mViewTag = viewTag;
mTimestampMs = SystemClock.uptimeMillis();
mInitialized = true;
@@ -43,6 +55,11 @@ public abstract class Event<T extends Event> {
return mViewTag;
}
/** @return the surfaceId for the view that generated this event */
public final int getSurfaceId() {
return mSurfaceId;
}
/**
* @return the time at which the event happened in the {@link android.os.SystemClock#uptimeMillis}
* base.
@@ -100,6 +117,17 @@ public abstract class Event<T extends Event> {
/** @return the name of this event as registered in JS */
public abstract String getEventName();
/** Dispatch this event to JS using the given event emitter. */
/**
* Dispatch this event to JS using the given event emitter. Compatible with old and new renderer.
*/
@Deprecated
public abstract void dispatch(RCTEventEmitter rctEventEmitter);
/**
* Dispatch this event to JS using a V2 EventEmitter. Events must explicitly override this, by
* default it uses the V1 dispatcher.
*/
public void dispatchV2(RCTModernEventEmitter rctEventEmitter) {
dispatch(rctEventEmitter);
}
}
@@ -14,7 +14,16 @@ import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
@DoNotStrip
@Deprecated
public interface RCTEventEmitter extends JavaScriptModule {
/**
* Deprecated in favor of RCTModernEventEmitter.receiveEvent.
*
* @param targetTag
* @param eventName
* @param event
*/
@Deprecated
void receiveEvent(int targetTag, String eventName, @Nullable WritableMap event);
void receiveTouches(String eventName, WritableArray touches, WritableArray changedIndices);
@@ -0,0 +1,24 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.uimanager.events;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.WritableMap;
/**
* This is a transitional replacement for RCTEventEmitter that works with Fabric and non-Fabric
* renderers. RCTEventEmitter works with Fabric as well, but there are negative perf implications
* and it should be avoided.
*
* <p>This interface will *also* be deleted in the distant future and be replaced with a new
* interface that doesn't need the old `receiveEvent` method at all. But for the foreseeable future,
* this is the recommended interface to use for EventEmitters.
*/
public interface RCTModernEventEmitter extends RCTEventEmitter {
void receiveEvent(int surfaceId, int targetTag, String eventName, @Nullable WritableMap event);
}