Android React Native原生模块与JS模块通信的方法总结

 更新时间:2017年02月11日 11:25:09   投稿:lqh  
这篇文章主要介绍了Android React Native原生模块与JS模块通信的方法总结的相关资料,需要的朋友可以参考下

Android React Native原生模块与JS模块通信的方法总结

前言:

在做React Native开发的时候避免不了的需要原生模块和JS之间进行数据传递,这篇文章将向大家分享原生模块向JS传递数据的几种方式。

方式一:通过Callbacks的方式

说起Callbacks大家都不陌生,它是最常用的设计模式之一。无论是Java,Object-c,C#,还是JavaScript等都会看到Callbacks的身影。

原生模块支持Callbacks类型的参数,该Callbacks对应JS中的function。

在原生模块中:

public class RNTestModule extends ReactContextBaseJavaModule{
  public RNTestModule(ReactApplicationContext reactContext) {
    super(reactContext);
  }
  @Override
  public String getName() {
    return "RNTest";
  }

 @ReactMethod
 public void measureLayout(
   int tag,
   int ancestorTag,
   Callback errorCallback,
   Callback successCallback) {
  try {
   measureLayout(tag, ancestorTag, mMeasureBuffer);
   map.putDouble("relativeX",1);
   map.putDouble("relativeY", 1);
   map.putDouble("width", 2);
   map.putDouble("height",3);
   successCallback.invoke(relativeX, relativeY, width, height);
  } catch (IllegalViewOperationException e) {
   errorCallback.invoke(e.getMessage());   
  }
}

在上述代码中,measureLayout方法的参数中后两个就是Callbacks,当原生模块处理成功时通过successCallback回调来告知JS处理成功的结果,当原生模块发生异常时,则通过errorCallback回调来JS处理异常。

在JS模块中:

RNTest.measureLayout(
 100,
 100,
 (msg) => {
  console.log(msg);
 },
 (x, y, width, height) => {
  console.log(x + ':' + y + ':' + width + ':' + height);
 }
);

上述代码,是在JS模块中调用原生模块的方法measureLayout,同时向它传递了四个参数,后两个是function类型的参数用于接收原生模块的处理结果。

通过上述的方式,JS调用原生模块的measureLayout方法,原生模块则通过errorCallback与successCallbackCallbacks来将处理结果传递到JS。

这种“You call me,I will callback”,的方式小伙伴们都看懂了吧。

方式二:通过Promises的方式

Promises是ES6的一个新的特性,在React Native中你会看到Promises的大量使用。

原生模块也是支持Promises的,这对喜欢使用Promises的小伙伴则是一个很好的消息。

在原生模块中:

public class RNTestModule extends ReactContextBaseJavaModule{
  public RNTestModule(ReactApplicationContext reactContext) {
    super(reactContext);
  }
  @Override
  public String getName() {
    return "RNTest";
  }
  @ReactMethod
  public void measureLayout(
      int tag,
      int ancestorTag,
      Promise promise) {
    try {
      WritableMap map = Arguments.createMap();
      map.putDouble("relativeX",1);
      map.putDouble("relativeY", 1);
      map.putDouble("width", 2);
      map.putDouble("height",3);

      promise.resolve(map);
    } catch (IllegalViewOperationException e) {
      promise.reject(e);
    }
  }
}

上述代码中,measureLayout方法接收的最后一个为Promise,当相应的处理结果出来之后原生模块通过调用Promise的相应方法来向JS模块传递处理成功,或处理失败的数据。

提示:在原生模块中Promise类型的参数要放在最后一位,这样JS调用的时候才能返回一个Promise。

在JS模块中:

async test() {
 try {
  var {
    relativeX,
    relativeY,
    width,
    height,
  } = await RNTest.measureLayout(100, 100);

  console.log(relativeX + ':' + relativeY + ':' + width + ':' + height); 
 } catch (e) {
  console.error(e);
 }
}

在上述代码中,通过ES7的新特性async/await来修饰了test方法,来以同步方式调用原生模块的measureLayout方法,如果原生模块处理成功,

那么JS中relativeX,relativeY,width,height会获得相应的值,如果原生模块处理失败,则会抛出异常。

如果,不希望以同步的形式调用,可以这样写:

test2(){
 RNTest.measureLayout(100,100).then(e=>{
  console.log(e.relativeX + ':' + e.relativeY + ':' + e.width + ':' + e.height);
  this.setState({
   relativeX:e.relativeX,
   relativeY:e.relativeY,
   width:e.width,
   height:e.height,
  })
 }).catch(error=>{
  console.log(error);
 });
}

以上就是通过Promises的方式向JS传递数据的方式,小伙伴们看懂了吗。

上述两种方式,通过Callbacks的方式与通过Promises的方式,都可以向JS模块传递数据,但都是只能传递一次。

如果,你需要多次向JS模块传递数据(如:按键事件)上述方式还是不够好,下面就像大家分享可以多次传递数据的方式。

方式三:通过发送事件的方式

原生模块支持另外一种向JS模块传递数据的方式,通过发送事件的方式。

原生模块,可以向JS传递事件而不要而不需要直接的调用,就像Android中的广播,iOS中的通知中心。

下面就向大家演示通过RCTDeviceEventEmitter,来向JS传递事件。

在原生模块中:

@Override
public void onHandleResult(String barcodeData) {
  WritableMap params = Arguments.createMap();
  params.putString("result", barcodeData);
  sendEvent(getReactApplicationContext(), "onScanningResult", params);
}

private void sendEvent(ReactContext reactContext,String eventName, @Nullable WritableMap params) {
  reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
      .emit(eventName, params);
}

上述代码向JS模块发送了一个名为“onScanningResult”的事件,并携带了“params”作为参数。

在JS模块中:

下面是在JS代码中进行监听原生模块发出的名为“onScanningResult”的事件。

componentDidMount() {
  //注册扫描监听
  DeviceEventEmitter.addListener('onScanningResult',this.onScanningResult);
}
onScanningResult = (e)=> {
  this.setState({
    scanningResult: e.result,
  });
  // DeviceEventEmitter.removeListener('onScanningResult',this.onScanningResult);//移除扫描监听
}

在JS中通过DeviceEventEmitter注册监听了名为“onScanningResult”的事件,当原生模块发出名为“onScanningResult”的事件后,绑定在该事件上的onScanningResult = (e)会被回调。

然后通过e.result就可获得事件所携带的数据。

心得:如果在JS中有多处注册了onScanningResult事件,那么当原生模块发出事件后,这几个地方会同时收到该事件。不过大家也可以通过DeviceEventEmitter.removeListener('onScanningResult',this.onScanningResult) 来移除对名为“onScanningResult”事件的监听。

另外,JS模块也支持通过Subscribable mixin,也注册监听事件,因为ES6已经不再推荐使用mixin,所以在这里也就不向大家介绍了。

三种方式的优缺点

方式 缺点 优点
通过Callbacks的方式 只能传递一次 传递可控,JS模块调用一次,原生模块传递一次
通过Promises的方式 只能传递一次 传递可控,JS模块调用一次,原生模块传递一次
通过发送事件的方式 原生模块主动传递,JS模块被动接收 可多次传递

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

相关文章

  • Android下使用TCPDUMP实现数据抓包教程

    Android下使用TCPDUMP实现数据抓包教程

    这篇文章主要介绍了Android下使用TCPDUMP实现数据抓包教程,本文讲解使用抓包工具tcpdump抓取数据,然后使用Wireshark来分析数据,需要的朋友可以参考下
    2015-02-02
  • android 图片操作(缩放移动) 实例代码

    android 图片操作(缩放移动) 实例代码

    android 图片操作(缩放移动) 实例代码,需要的朋友可以参考一下
    2013-06-06
  • Android开发实现SubMenu选项菜单和子菜单示例

    Android开发实现SubMenu选项菜单和子菜单示例

    这篇文章主要介绍了Android开发实现SubMenu选项菜单和子菜单,结合实例形式分析了Android开发中SubMenu选项菜单和子菜单的功能、配置、布局等相关操作技巧,需要的朋友可以参考下
    2019-03-03
  • Kotlin 协程 supervisorScope {} 运行崩溃解决方法

    Kotlin 协程 supervisorScope {} 运行崩溃解决方法

    看过很多 supervisorScope {} 文档的使用,我照抄一摸一样的代码,运行就崩溃,最后找到了解决方法,应该是kotlin版本更新做过改动,当前我使用的是 androidx.core:core-ktx:1.9.0,本文给大家介绍Kotlin 协程 supervisorScope {} 运行崩溃解决方法,感兴趣的朋友一起看看吧
    2024-01-01
  • Android编程自定义菜单实现方法详解

    Android编程自定义菜单实现方法详解

    这篇文章主要介绍了Android编程自定义菜单实现方法,结合实例形式分析了Android自定义菜单的布局、动画及功能相关实现技巧与注意事项,需要的朋友可以参考下
    2017-02-02
  • Android开发入门之Appwidget用法分析

    Android开发入门之Appwidget用法分析

    这篇文章主要介绍了Android开发入门之Appwidget用法,较为详细的分析了App Widget的概念、功能、创建、使用方法与相关注意事项,需要的朋友可以参考下
    2016-07-07
  • Android Kotlin的使用及简单实例

    Android Kotlin的使用及简单实例

    这篇文章主要介绍了Android Kotlin的使用及简单实例的相关资料,需要的朋友可以参考下
    2017-05-05
  • android基础教程之夜间模式实现示例

    android基础教程之夜间模式实现示例

    这篇文章主要介绍了android的夜间模式实现示例,需要的朋友可以参考下
    2014-02-02
  • 详解Android 扫描条形码(Zxing插件)

    详解Android 扫描条形码(Zxing插件)

    本篇文章主要对Android 扫描条形码(Zxing插件)进行实例解析,相信对大家的学习会有很好的帮助,需要的朋友一起来看下吧
    2016-12-12
  • Android实现Unity3D下RTMP推送的示例

    Android实现Unity3D下RTMP推送的示例

    像Unity3D下的RTMP或RTSP播放器一样,好多开发者苦于在Unity环境下,如何高效率低延迟的把数据采集并编码实时推送到流媒体服务器,实现Unity场景下的低延迟推拉流方案。本文介绍几种RTMP推送的方案
    2021-06-06

最新评论