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模块被动接收 | 可多次传递 |
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!