当前位置: 移动技术网 > IT编程>移动开发>Android > Android React Native原生模块与JS模块通信的方法总结

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

2019年07月24日  | 移动技术网IT编程  | 我要评论

酷基网,赛尔号打雷伊,不掉毛的狗

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模块被动接收 可多次传递

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网