編輯:關於Android編程
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模塊被動接收
可多次傳遞
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
Mono for Android 實現高效的導航(Effective Navigation)
Android 4.0 系統定義了一系列的高效導航方式 (Effective Navigation), 主要包括標簽、下拉列表、以及向上和返回等, 本文介紹如何用 Mon
android中AES加解密的使用方法
今天在android項目中使用AES對數據進行加解密,遇到了很多問題,網上也找了很多資料,也不行。不過最後還是讓我給搞出來了,這裡把這個記錄下來,不要讓別人走我的彎路,因
Android官方文檔之Location and Sensors APIs(下)
本文將介紹運動傳感器(Motion Sensors)、位置傳感器(Position Sensors)、環境傳感器(Environment Sensors)。如需訪問官方原
Android App中使用LinearLayout進行居中布局的實例講解
要想讓您的控件水平居中或垂直居中其實很簡單,只要在控件的上一級中設置【android:gravity=center】屬性即可如:<LinearLayout xmln