You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 19:06:29