Android模塊化及RN調(diào)用原生

Android模塊化及RN調(diào)用原生

先老實(shí)交代下背景,這篇講的是兩個(gè)問(wèn)題。這兩個(gè)問(wèn)題是自己被問(wèn)到的,但是講的很含糊,想必問(wèn)我的人也不滿意吧。究其原因:語(yǔ)言組織、表達(dá)、緊張。都是淚,下面說(shuō)說(shuō)這兩個(gè)問(wèn)題吧。

Q1:android模塊化遇到的問(wèn)題?

按照原始MVP的架構(gòu),隨著業(yè)務(wù)越來(lái)越復(fù)雜、基礎(chǔ)組件越來(lái)越多。業(yè)務(wù)與業(yè)務(wù)之間還有很強(qiáng)的耦合。就變成這樣

復(fù)雜業(yè)務(wù)

使用模塊化之后,變成這樣

模塊化

很明顯清晰了不少。那么模塊化又存在哪些問(wèn)題呢?

  1. 最常見(jiàn)的R文件問(wèn)題。
    我當(dāng)時(shí)說(shuō)的時(shí)候:整體與個(gè)體之間沖突,findbyid常用的ButterKnife不能用,因?yàn)闀?huì)有沖突等。module的application和主app的application沖突。

總之沒(méi)有很系統(tǒng)的講出來(lái),估計(jì)對(duì)方也不耐煩了。尷了個(gè)噶。接下來(lái)正規(guī)系統(tǒng)的講下:

Android開(kāi)發(fā)中,各個(gè)資源文件都是放在res目錄中,在編譯過(guò)程中,會(huì)生成R.java文件。R文件中包含有各個(gè)資源文件對(duì)應(yīng)的id,這個(gè)id是靜態(tài)常量,但是在Library Module中,這個(gè)id不是靜態(tài)常量,那么就會(huì)出現(xiàn)找不到id或者id沖突這樣的問(wèn)題。因此常用的ButterKnite也不能使用

解決方案:

  1. 重新一個(gè)Gradle插件,生成一個(gè)R2.java文件,這個(gè)文件中各個(gè)id都是靜態(tài)常量,這樣ButterKnite就可以正常使用了,通過(guò)R2獲取到id。
  2. 使用Android系統(tǒng)提供的最原始的方式,直接用findViewById以及setOnClickListener方式。
  3. 設(shè)置項(xiàng)目支持Databinding,然后使用Binding中的對(duì)象,但是會(huì)增加不少方法數(shù),同時(shí)Databinding也會(huì)有編譯問(wèn)題和學(xué)習(xí)成本。目前項(xiàng)目中沒(méi)有使用Databinging,這里也沒(méi)有太多的發(fā)言權(quán)
  1. xml沖突,資源沖突問(wèn)題

解決辦法:

  1. 對(duì)各個(gè)模塊的資源名字添加前綴,比如user模塊中的登錄界面布局為activity_login.xml,那么可以寫(xiě)成這樣us_activity_login.xml。
  2. application的xml只能查查哪些屬性沖突,借助網(wǎng)上資料了。

總結(jié)

模塊化架構(gòu)主要思路就是分而治之,把依賴整理清楚,減少代碼冗余和耦合,在把代碼抽取到各自的模塊后,了解各個(gè)模塊的通信方式,以及可能發(fā)生的問(wèn)題,規(guī)避問(wèn)題或者解決問(wèn)題。最后為了開(kāi)發(fā)和調(diào)試方便,開(kāi)發(fā)一些周邊工具,幫助開(kāi)發(fā)更好的完成任務(wù)。

Q2 ReactNative如何調(diào)用Android原生模塊

先來(lái)說(shuō)說(shuō)我的回答:android原生模塊實(shí)現(xiàn)ReactContext,通過(guò)它的回調(diào)使用原生模塊的方法?,F(xiàn)在回想太通俗了。下面正規(guī)說(shuō)下:

  1. 創(chuàng)建一個(gè)原生模塊
    首先我們需要?jiǎng)?chuàng)建一個(gè)原生模塊,這個(gè)原生模塊是一個(gè)繼承ReactContextBaseJavaModule的Java類,它可以實(shí)現(xiàn)一些JavaScript所調(diào)用的原生功能.
public class RnTest extends ReactContextBaseJavaModule {
  public RnTest(ReactApplicationContext reactContext) {
    super(reactContext);
  }
  // ReactContextBaseJavaModule要求派生類實(shí)現(xiàn)getName方法。這個(gè)函數(shù)用于返回一個(gè)字符串
  // 這個(gè)字符串用于在JavaScript端標(biāo)記這個(gè)原生模塊
  @Override
  public String getName() {
    return "ToastByAndroid";
  }
  // 獲取應(yīng)用包名
  // 要導(dǎo)出一個(gè)方法給JavaScript使用,Java方法需要使用注解@ReactMethod
   @ReactMethod
   public void getPackageName() {
     String name = getReactApplicationContext().getPackageName();
     Toast.makeText(getReactApplicationContext(),name,Toast.LENGTH_LONG).show();
    }
}
  1. 注冊(cè)模塊
    要使JavaScript端調(diào)用到原生模塊還需注冊(cè)這個(gè)原生模塊。需實(shí)現(xiàn)一個(gè)類實(shí)現(xiàn)ReactPackage接口
public class ExampleReactPackage implements ReactPackage {
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
      List<NativeModule> modules = new ArrayList<>();
      modules.add(new RnTest(reactContext));
      return modules;
    }

    @Override
    public List<Class<? extends JavaScriptModule>> createJSModules() {
      return Collections.emptyList();
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
      return Collections.emptyList();
    }
}

還需在MainApplication.java文件中的getPackages方法中,實(shí)例化上面的注冊(cè)類

@Override
  protected List<ReactPackage> getPackages() {
    return Arrays.<ReactPackage>asList(
      new MainReactPackage(),
      // 實(shí)例化注冊(cè)類
      new ExampleReactPackage());
    }
  };
  1. js調(diào)用android原生

    1. 引入模塊
      import { NativeModules } from 'react-native';
    2. 使用方法
//  這里的ToastByAndroid即為1.創(chuàng)建一個(gè)原生模塊中g(shù)etName()方法返回的字符串
var rnToastAndroid = NativeModules.ToastByAndroid;
rnToastAndroid.getPackageName();
3. 回調(diào)函數(shù)

提供給js調(diào)用的原生android方法的返回類型必須是void,React Native的跨語(yǔ)言訪問(wèn)是異步進(jìn)行的,所以想要給JavaScript返回一個(gè)值的唯一辦法是使用回調(diào)函數(shù)或者發(fā)送事件

android主動(dòng)向rn發(fā)送消息

既然都說(shuō)道js向原生調(diào)用了,那么也說(shuō)說(shuō)原生向js調(diào)用。

根據(jù)上面,可以想到的思路就是:通過(guò)reactContext獲取到j(luò)sModule,然后像eventbus一樣發(fā)生事件,js方獲取事件。

  1. 創(chuàng)建一個(gè)原生模塊,發(fā)送消息方法
public  static void sendEvent(ReactContext reactContext, String eventName, int status)
    {
        System.out.println("reactContext="+reactContext);

        reactContext
                .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit(eventName,status);
    }
    ```


2. RN端代碼

DeviceEventEmitter.addListener(eventName, (reminder) => {
console.log(reminder):
});
```

  1. rn調(diào)用android模版
const RNBridgeModule = NativeModules.RNBridgeModule;
nativeLanuchApp(message) {
    RNBridgeModule.nativePlayVideo(message);
  }

  <TouchableOpacity onPress={() => {
                            this.nativeLanuchApp("111");
                        }} >
      <Text >
        try
      </Text>
    </TouchableOpacity>
    ```
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,765評(píng)論 25 709
  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時(shí)...
    歐辰_OSR閱讀 30,194評(píng)論 8 265
  • 第一彈【小火鍋】 每個(gè)月總有那么幾天,我特別想去校門口吃小火鍋。 想吃了直接就進(jìn)屋坐下,叫份鍋底,選擇好自己喜歡的...
    桃啃笙閱讀 659評(píng)論 0 1
  • 經(jīng)歷了好些事情,感嘆生活真的不容易,好多事情也不如心里所想。 去年是我的本命年,我總怪時(shí)運(yùn)不濟(jì),不走運(yùn)、倒霉。而到...
    駐足現(xiàn)在閱讀 693評(píng)論 0 0
  • (一) 那只貓來(lái)的那天傍晚,下大雨,我心情很壞。 下午攜程的產(chǎn)品推介會(huì)結(jié)束,我下樓,給彭大花打電話。我...
    安蔚閱讀 716評(píng)論 0 0

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