ReactNative跟Android原生模塊是如何進(jìn)行數(shù)據(jù)交互實例

引文:有時候App需要訪問平臺API,但React Native可能還沒有相應(yīng)的模塊包裝;或者你需要復(fù)用一些Java代碼,而不是用Javascript重新實現(xiàn)一遍;又或者你需要實現(xiàn)某些高性能的、多線程的代碼,譬如圖片處理、數(shù)據(jù)庫、或者各種高級擴(kuò)展等等。
來自:https://reactnative.cn/docs/0.51/native-modules-android.html#content

看了上面的那段引文以及那篇文檔我們大致懂得在Android客戶端中如何封裝原生模塊給RN使用,本文作為補(bǔ)充說明用一些實例來更詳細(xì)的理解RN跟客戶端是如何交互。

基礎(chǔ)數(shù)據(jù)類型

自定義原生模塊給RN調(diào)用的話那么就得將Java對應(yīng)的數(shù)據(jù)類型轉(zhuǎn)換成JS可以識別的數(shù)據(jù)類型:

Boolean -> Bool
Integer -> Number
Double -> Number
Float -> Number
String -> String
Callback -> function
ReadableMap -> Object
ReadableArray -> Array

其中Callback、ReadableMap、ReadableArray這個三個除外其他的數(shù)據(jù)類型還是比較常見的,所以這里將針對每種數(shù)據(jù)類型都舉例子來明白是如何轉(zhuǎn)換和調(diào)用的。

這里假裝你看過引用的文檔并聲明相關(guān)的類...............................

常見的數(shù)據(jù)類型< Boolean、Integer、Double、Float、String >

先在AndroidStudio中定義一個類并且實現(xiàn)ReactContextBaseJavaModule類,然后聲明一個函數(shù)并用@ReactMethod聲明注釋:

@ReactMethod
public void show(boolean _boolean, int _int, double _double, float _float, String _string) {
    Log.w("Jayuchou", "=== boolean Message = " + _boolean);
    Log.w("Jayuchou", "=== int Message = " + _int);
    Log.w("Jayuchou", "=== double Message = " + _double);
    Log.w("Jayuchou", "=== float Message = " + _float);
    Log.w("Jayuchou", "=== String Message = " + _string);
}

然后這時候開始寫一個RN的代碼來調(diào)用這個原生模塊的show方法,然后我們根據(jù)打印的結(jié)果來清楚這些常見的數(shù)據(jù)類型是長怎樣的以及怎么調(diào)用。

首先RN代碼中聲明一下原生模塊:

// NativeModules后面對應(yīng)的是ToastModule是原生模塊對應(yīng)的name即可
const ToastModule = NativeModules.ToastModule;

然后RN中簡單采用Text并給他賦值一個點擊事件,當(dāng)我們點擊該Text的時候就傳遞數(shù)據(jù)給原生模塊:

// ToastModule.show是一個我們定義的原生方法
<Text onPress={() => {
    ToastModule.show(false, 1, 1.0, 2.0, "來自ES6..");
}}>
    基礎(chǔ)類型使用用例
</Text>

當(dāng)然我們調(diào)用ToastModule.show的時候數(shù)據(jù)類型要嚴(yán)格按照原生定義的類型來傳,不然容易報類型轉(zhuǎn)換錯誤:

// 打印結(jié)果:  很顯然都是RN傳遞給原生模塊的數(shù)據(jù)
=== boolean Message = false
=== int Message = 1
=== double Message = 1.0
=== float Message = 2.0
=== String Message = 來自ES6..

ReadableMap/ReadableArray實例

還是老樣子直接上代碼,并直接把結(jié)果打印出來 直接看注釋:

// 一個帶ReactMethod的方法并傳入ReadableMap ReadableArray
@ReactMethod
public void showReadable(ReadableMap object, ReadableArray array) {
    Log.w("Jayuchou", "=== ReadableMap = " + object.getString("name"));
    Log.w("Jayuchou", "=== ReadableArray[0] = " + array.getString(0));
    Log.w("Jayuchou", "=== ReadableArray[1] = " + array.getInt(1));
}

/**
首先要明白:
ReadableMap對應(yīng)Js的語法是Object  而  ReadableArray對應(yīng)的語法是Array
*/

// ReadableMap我們直接傳對象{name: "Neacy"}
// ReadableArray我們傳["Jayuchou", 100]
<Text style={styles.instructions} onPress={() => {
    ToastModule.showReadable({name: "Neacy"}, ["Jayuchou", 100]);
}}>
    Object/Array轉(zhuǎn)ReadableMap/ReadableArraay
</Text>

// 打印結(jié)果
=== ReadableMap = Neacy
=== ReadableArray[0] = Jayuchou
=== ReadableArray[1] = 100

Callback實例

常見的數(shù)據(jù)類型都是RN傳遞給原生使用,很顯然平時開發(fā)不會這么簡單往往我們需要客戶端處理完結(jié)果后回調(diào)給RN,這里聲明一個函數(shù)直接將傳入的參數(shù)相加并將結(jié)果通過callback回調(diào)回去。

@ReactMethod
public void add(int a, int b, Callback callback) {
    callback.invoke("CallBack的結(jié)果是 = " + (a + b));
}

在RN代碼中直接調(diào)用ToastModule.add方法,注意最后是一個參數(shù)是一個函數(shù),Callback往往用于做同步操作的時候比較多一點。

// 這里將通過原生計算后的結(jié)果通過setState來刷新界面并顯示出來: 效果看文章附圖
<Text style={styles.welcome} onPress={() => {
    ToastModule.add(1, 2, (result) => {
        this.setState({name: result});
    })
}}>
    CallBack使用用例
</Text>

Promise實例

很明顯有了Callback已經(jīng)可以回調(diào)數(shù)據(jù)了,為什么還要Promise呢? 為了異步,用Promise就是我們可以通過原生異步處理一個耗時的然后再將結(jié)果傳給RN端:

@ReactMethod
public void doRequest(final Promise promise) {
    Observable.create(new ObservableOnSubscribe<String>() {
        @Override
        public void subscribe(ObservableEmitter<String> e) throws Exception {
            e.onNext("Promise的結(jié)果 = Neacy");
            e.onComplete();
        }
    }).subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<String>() {
        @Override
        public void accept(String s) throws Exception {
            WritableMap wMap = new WritableNativeMap();
            wMap.putString("name", s);
            promise.resolve(wMap);
        }
    }, new Consumer<Throwable>() {
        @Override
        public void accept(Throwable throwable) throws Exception {
            promise.reject(throwable);
        }
    });
}

有沒有覺得采用RxJava跟Promise真的好配。

// 定義一個promise異步請求,采用ES6的async await語法糖
async getInfo() {
    this.setState(await ToastModule.doRequest());
}

// 點擊按鈕觸發(fā)請求,同樣請求的結(jié)果放到state中 結(jié)果查看附圖。
<Text style={styles.welcome} onPress={() => {
    this.getInfo();
}}>
    Promise使用用例
</Text>

DeviceEventEmitter實例
常見的數(shù)據(jù)交互除了RN主動和客戶端交互外,客戶端還可以通過DeviceEventEmitter將數(shù)據(jù)直接發(fā)給RN端,當(dāng)然RN端需要接收。

WritableMap map = Arguments.createMap();
map.putString("name", "=== 這是DeviceEventEmitter結(jié)果 ===");
// 傳一個WriteableMap給RN
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("neacy", writableMap);

// 直接傳一個String給RN
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("neacy", "=== DeviceEventEmitter的是字符串 ===");

然后RN設(shè)置監(jiān)聽,一般會在componentWillMount方法組件加載完成后設(shè)置監(jiān)聽:

componentWillMount() {
    DeviceEventEmitter.addListener('neacy', (result) => {
        this.setState({name: result});
    })
}

附圖
上面是一個個Text可以點擊相對應(yīng)的來查看交互結(jié)果:

這里寫圖片描述

這就是常見的RN跟Android原生交互的一些方案:

  1. 直接傳數(shù)據(jù)給Android端,然后Android端可以異步或者同步處理并通過Promise或者Callback回調(diào)數(shù)據(jù)給RN端顯示。
  2. Android端通過DeviceEventEmitter主動和RN端進(jìn)行交互。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容