React Native原生模塊向JS傳遞數據的幾種方式(Android)

在做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 與 successCallback Callbacks來將處理結果傳遞到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傳遞數據的方式,小伙伴們看懂了嗎。

上述兩種方式,與,都可以向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模塊被動接收 可多次傳遞

 

 

來自:http://www.cboy.me/2016/09/29/React-Native原生模塊向JS傳遞數據的幾種方式/

 

 本文由用戶 erjnae9012 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!