RN 的EventEmitter 双向通信

0 阅读2分钟

React Native 的 EventEmitter 双向通信,本质是 JS 和 Native 之间通过事件机制互相通知

它和普通 Native Module 方法调用不同:

  • Native Module:JS 主动调用 Native
  • EventEmitter:Native 和 JS 都可以主动发送事件

通信模型:

        JS
        |
        | emit / addListener
        |
 React Native Bridge
        |
        |
      Native

一、JS → Native(主动调用)

这个不是 EventEmitter 最典型场景,一般用 Native Module。

例如:

JS:

NativeModules.DeviceModule.start();

Native:

@ReactMethod
public void start(){
    //执行原生逻辑
}

流程:

JS
 |
Bridge
 |
Native Module
 |
Java/Kotlin

二、Native → JS(EventEmitter)

这是 EventEmitter 最常见用途。

例如:

Android 检测到:

  • 蓝牙状态变化
  • GPS变化
  • 推送消息
  • 传感器数据

Native:

sendEvent(
    "onLocationChanged",
    params
);

JS监听:

DeviceEventEmitter.addListener(
    "onLocationChanged",
    data=>{
        console.log(data);
    }
);

流程:

Android
 |
emit事件
 |
Bridge
 |
JS Listener

三、Android实现 EventEmitter

1. Native Module继承

public class DeviceModule 
extends ReactContextBaseJavaModule {

    private ReactApplicationContext context;


    public DeviceModule(
        ReactApplicationContext context
    ){
        super(context);
        this.context=context;
    }


    @Override
    public String getName(){
        return "DeviceModule";
    }

}

2. 发送事件

private void sendEvent(
    String eventName,
    WritableMap params
){

    context
    .getJSModule(
        DeviceEventManagerModule.RCTDeviceEventEmitter.class
    )
    .emit(
        eventName,
        params
    );
}

这里:

RCTDeviceEventEmitter

就是 RN 的事件桥。


3. 调用

比如:

WritableMap data =
Arguments.createMap();

data.putString(
 "message",
 "hello JS"
);


sendEvent(
 "DeviceEvent",
 data
);

四、JS监听

RN 新版本推荐:

import {
 NativeEventEmitter,
 NativeModules
} from 'react-native';


const {
 DeviceModule
}=NativeModules;


const emitter =
new NativeEventEmitter(DeviceModule);



const subscription =
emitter.addListener(
 "DeviceEvent",
 data=>{
    console.log(data);
 }
);

取消监听:

subscription.remove();

否则容易:

Memory Leak

五、JS → Native事件

如果 JS 想发事件给 Native:

例如:

JS:

DeviceEventEmitter.emit(
 "Login",
 {
  user:"Tom"
 }
);

但是:

Native 默认不能直接监听 JS EventEmitter。

通常做法:

JS调用Native Module

NativeModules.UserModule.login(
{
 user:"Tom"
}
);

Native:

@ReactMethod
public void login(
ReadableMap data
){

}

也就是说:

JS ---> Native

推荐:
Native Module

不是 EventEmitter

六、完整双向模型

                 JS

          NativeEventEmitter
                 ↑
                 |
        Native ---> JS
        emit事件



          Native Module
                 ↑

        JS ---> Native
        method调用

                 Native

七、实际项目例子:扫码

JS启动扫码

Scanner.start();

Native:

startCamera();

扫码成功:

emit(
 "ScanResult",
 {
   code:"123456"
 }
);

JS:

scannerEmitter.addListener(
"ScanResult",
(result)=>{
 console.log(result.code);
});

八、RN 新架构(TurboModule)

旧架构:

JS
 |
Bridge
 |
EventEmitter
 |
Native

新架构:

JS
 |
JSI
 |
TurboModule
 |
Native

事件通常使用:

  • TurboModule
  • EventEmitter interface
  • Codegen

例如:

TypeScript:

export interface Spec
extends TurboModule {

 readonly onChange:
 EventEmitter<string>;

}

Codegen 自动生成绑定。


总结

方向推荐方式
JS调用NativeNative Module
Native通知JSNativeEventEmitter
持续数据流EventEmitter
一次请求返回Promise/Callback
新架构TurboModule + EventEmitter

实际开发中:

  • 蓝牙状态
  • 推送
  • GPS
  • NFC
  • 扫码
  • 原生播放器状态

基本都是:

JS调用Native启动
        ↓
Native持续emit事件
        ↓
JS监听更新UI

这就是 RN EventEmitter 最典型的双向通信模式。