上一篇文章[React Native]原生模塊(上)中我們介紹了原生模塊的基本用法魏身,本篇文章將介紹原生模塊的高級(jí)用法—ReactNative與原生模塊的通信方式老虫。
由于本文涉及到很多React方面的知識(shí),比如state企蹭、生命周期等,沒有接觸過的同學(xué)建議首先閱讀下阮一峰老師的React入門實(shí)例教程
通信方式總共分為以下三種:
- Callback
- Promise
- Event
本文將演示原生模塊使用Thread
異步執(zhí)行方法后回調(diào)JS
模塊,并在界面上顯示出線程的名字和執(zhí)行時(shí)間竖配,效果圖如下
首先,按照上一篇文章[React Native]原生模塊(上)的步驟
1里逆、新建一個(gè)ReactNative
項(xiàng)目
2甚颂、并創(chuàng)建名稱為NativeAndroid
的原生模塊
3、最后完成他的注冊(cè)工作
此時(shí)漏策,NativeAndroid
的代碼如下
public class NativeModule extends ReactContextBaseJavaModule {
ReactApplicationContext mReactContext;
public NativeModule(ReactApplicationContext reactContext) {
super(reactContext);
mReactContext = reactContext;
}
@Override
public String getName() {
return "NativeAndroid";
}
}
4圾另、在index.android.js
中用TouchableOpacity
包裹三個(gè)可點(diǎn)擊的View
:Callback
、Promise
诸衔、Event
render() {
return (
<View style={styles.container}>
<TouchableOpacity onPress={()=>{
}}>
<Text style={styles.welcome}>
Callback
</Text>
</TouchableOpacity>
<TouchableOpacity onPress={()=>{
}}>
<Text style={styles.welcome}>
Promise
</Text>
</TouchableOpacity>
<TouchableOpacity onPress={()=>{
}}>
<Text style={styles.welcome}>
Event
</Text>
</TouchableOpacity>
</View>
);
}
5盯漂、在index.android.js
中新建一個(gè)state
:result
簡單理解就是一個(gè)特殊的屬性,一旦修改它的值笨农,會(huì)觸發(fā)render方法就缆,這樣頁面就得到刷新了。對(duì)這個(gè)用法不了解的同學(xué)谒亦,可以參考阮一峰老師的React入門實(shí)例教程
// es6語法竭宰,如果使用React.createClass則使用getInitialState
constructor () {
super();
this.state = {
result: ''
}
}
render() {
return (
<View style={styles.container}>
// 此處代碼省略若干行
<Text style={styles.instructions}>
{this.state.result}
</Text>
</View>
);
}
準(zhǔn)備步驟到此結(jié)束了。
下面份招,我們分別介紹三種實(shí)現(xiàn)方式
- Callback
回調(diào)函數(shù)切揭,對(duì)應(yīng)
JS
中的function
1、在NativeModule
中新建testCallback
方法 锁摔,包含一個(gè)參數(shù)Callback
(對(duì)應(yīng)JS
的function
)
@ReactMethod
public void testCallback(final Callback callback)
{
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
callback.invoke("Callback: " + Thread.currentThread().getName() + " has slept 3 ms.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
2廓旬、在Callback
的onPresss
方法中調(diào)用testCallback
方法
<TouchableOpacity onPress={()=>{
NativeAndroid.testCallback((msg)=>{
this.setState({result: msg});
});
}}>
<Text style={styles.welcome}>
Callback
</Text>
</TouchableOpacity>
這里給testCallback
方法傳遞了一個(gè)箭頭函數(shù),并將返回值msg
賦值給result
谐腰,然后會(huì)觸發(fā)render
方法刷新界面孕豹。
- Promise
這里涉及到
ES7
標(biāo)準(zhǔn)的JS
語法,需要配合async/await
來使用怔蚌。橋接的原生方法的最后一個(gè)參數(shù)為Promise
1巩步、在NativeModule
中新建testPromise
方法 ,包含一個(gè)參數(shù)Promise
(當(dāng)然桦踊,你也可以同時(shí)傳遞其他參數(shù))
@ReactMethod
public void testPromise(final Promise promise)
{
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
WritableMap map = Arguments.createMap();
map.putString("msg", "Promise: " + Thread.currentThread().getName() + " has slept 3 ms.");
promise.resolve(map);
} catch (InterruptedException e) {
promise.reject("InterruptedException", e);
}
}
}).start();
}
這里椅野,使用promise.resolve
來傳遞一個(gè)WritableMap
,使用promise.reject
來傳遞錯(cuò)誤信息
WritableMap類似一個(gè)字典,用來包裝多個(gè)輸出參數(shù)給
JS
模塊
2竟闪、在index.android.js
文件的class
新建一個(gè)方法promise
离福,方法需要使用async
來修飾
// es7語法,Promise必須配合async使用
async promise()
{
try {
var {
msg
} = await NativeAndroid.testPromise();
this.setState({result: msg});
} catch (error) {
console.log(error);
}
}
這里炼蛤,var {msg} = await NativeAndroid.testPromise();
中的msg
對(duì)應(yīng)原生方法public void testPromise(final Promise promise)
的語句promise.resolve(map);
中map
傳遞的參數(shù)msg
妖爷,最后使用this.setState({result: msg});
來刷新界面
3、在Promise
的onPress
方法中調(diào)用promise
方法
<TouchableOpacity onPress={()=>{
this.promise();
}}>
<Text style={styles.welcome}>
Promise
</Text>
</TouchableOpacity>
- Event
1理朋、原生模塊可以在沒有被調(diào)用的情況下往JavaScript發(fā)送事件通知絮识。最簡單的辦法就是通過RCTDeviceEventEmitter,這可以通過ReactContext來獲得對(duì)應(yīng)的引用嗽上,像這樣:
mReactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("事件名稱", Object);
2次舌、原生模塊可以主動(dòng)通知
JS
模塊,這里為了簡單起見兽愤,還是通過JS
觸發(fā)原生方法彼念,原生方法再發(fā)送事件到JS
模塊
1、在NativeModule
中新建testEvent
方法
/**
* 發(fā)送事件到JS
* [為了簡單演示浅萧,從JS調(diào)用此方法再發(fā)送事件到JS]
*/
@ReactMethod
public void testEvent()
{
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
mReactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("testEvent", "Event: " + Thread.currentThread().getName() + " has slept 3 ms.");
} catch (InterruptedException e) {
}
}
}).start();
}
2逐沙、在JS
模塊組件Component
的生命周期函數(shù)componentWillMount
中注冊(cè)事件監(jiān)聽,并在收到通知后刷新界面
componentWillMount()
{
DeviceEventEmitter.addListener('testEvent', (msg) => {
this.setState({result: msg});
});
}
當(dāng)然洼畅,你需要引入DeviceEventEmitter
import {
// ...省略若干行代碼
DeviceEventEmitter
} from 'react-native';
3吩案、在Event
的onPress
方法中調(diào)用testEvent
方法
<TouchableOpacity onPress={()=>{
NativeAndroid.testEvent();
}}>
<Text style={styles.welcome}>
Event
</Text>
</TouchableOpacity>
最后,讓我們?cè)俅慰聪伦罱K效果圖
本文的源碼地址:Demo3