Android Fabric组件中RCTModernEventEmitter点击触发两次问题求助
Android Fabric组件点击事件触发两次问题修复
我在开发Android端Fabric组件时,希望通过RCTModernEventEmitter将按钮的onClickHandler回调传递到React Native端。该功能在iOS上运行正常,但Android端每次点击按钮,RCTModernEventEmitter都会触发两次回调。
Spec代码
import type {HostComponent, ViewProps} from 'react-native'; import type { DirectEventHandler } from 'react-native/Libraries/Types/CodegenTypes'; import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent'; type Event = Readonly<{ text?: string; }>; interface NativeProps extends ViewProps { text: string; onClickHandler?: DirectEventHandler<Event>; // 事件名需以on开头 } export default codegenNativeComponent<NativeProps>( 'MyButtonView', ) as HostComponent<NativeProps>;
Android原生代码
MyButtonViewManager.java
public class MyButtonViewManager extends SimpleViewManager<MyButtonView> { public static final String NAME = "MyButtonView"; ReactApplicationContext mCallerContext; public MyButtonViewManager(ReactApplicationContext reactContext) { mCallerContext = reactContext; } @NonNull @Override public String getName() { return NAME; } @NonNull @Override protected MyButtonView createViewInstance(@NonNull ThemedReactContext reactContext) { return new MyButtonView(reactContext); } @ReactProp(name = "text") public void setQrCodeText(MyButtonView view, String text) { view.setText(text); } @Nullable @Override public Map<String, Object> getExportedCustomDirectEventTypeConstants() { return MapBuilder.of("topOnClickHandler", MapBuilder.of("registrationName", "onClickHandler") ); } }
MyButtonClickEvent.java
public class MyButtonClickEvent extends Event<MyButtonClickEvent> { public MyButtonClickEvent(int viewId) { super(viewId); } @Override public String getEventName() { return "topOnClickHandler"; } // @Override // public void dispatch(RCTEventEmitter rctEventEmitter) { // super.dispatch(rctEventEmitter); // rctEventEmitter.receiveEvent(getViewTag(), getEventName(), Arguments.createMap()); // } @Override public void dispatchModern(RCTModernEventEmitter rctEventEmitter) { super.dispatchModern(rctEventEmitter); rctEventEmitter.receiveEvent(-1, getViewTag(),getEventName(), Arguments.createMap() ); } @Nullable @Override protected WritableMap getEventData() { WritableMap event = Arguments.createMap(); event.putString("message", "MyMessage"); return event; } }
MyButtonView.java
public class MyButtonView extends androidx.appcompat.widget.AppCompatButton { public MyButtonView(Context context) { super(context); configureViews(); } private void configureViews(){ setBackgroundColor(Color.YELLOW); setOnClickListener(view -> { ReactContext reactContext = (ReactContext)getContext(); EventDispatcher eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag( reactContext ,getId() ); eventDispatcher.dispatchEvent(new MyButtonClickEvent(getId())); }); } }
JS端代码
<MyButtonView style={{height: 100, width: 100, margin: 20}} onClickHandler={(value: any) => { console.log('Hello ok bye', value.nativeEvent); }} text="Hello" />
问题原因及修复
问题出在MyButtonClickEvent的dispatchModern方法中:调用super.dispatchModern(rctEventEmitter)后,父类方法已经自动完成了事件分发,同时手动调用rctEventEmitter.receiveEvent导致事件被重复分发两次。
修改后的MyButtonClickEvent.java
移除父类方法调用,直接使用自定义的事件数据分发:
@Override public void dispatchModern(RCTModernEventEmitter rctEventEmitter) { rctEventEmitter.receiveEvent( getCoalescingKey(), getViewTag(), getEventName(), getEventData() ); }
也可以选择保留父类逻辑,删除手动的receiveEvent调用,父类会自动使用getEventData()返回的内容:
@Override public void dispatchModern(RCTModernEventEmitter rctEventEmitter) { super.dispatchModern(rctEventEmitter); }
修改后点击按钮即可触发一次回调,与iOS端行为保持一致。
内容的提问来源于stack exchange,提问作者BraveEvidence
相关产品推荐
相关产品推荐

