學習React-Native-如果啟動并第一個View

React-Native 版本: 0.52.0

React-Native 本質上來說其實就是一個普通的Android應用。通過Layout Inspector查看UI的層級結構如下:

一個普通的App签赃。Java類一共有兩個MainApplication和MainActivity谷异。入口肯定也是MainApplication的onCreate,啟動Activity就是MainActivity锦聊。

MainApplication

MainApplication很簡單歹嘹,實現了ReactApplication,構造一個ReactNativeHost孔庭。而ReactNativeHost就比較的復雜了尺上,最重要的是創(chuàng)建并擁有了一個ReactInstanceManager材蛛。它還做一些native和js交互的一些配置,
例如getBundleAssetName()配置js入口的文件名字怎抛,getPackages()配置js與原生交互的模塊組件等卑吭。

MainActivity

主要的工作在它的父類ReactActivity當中,這個很復雜马绝,做了絕大多的事豆赏。

這里用了一個代理模式,ReactActivityDelegate代理了ReactActivity的生命周期的方法和其他一些方法迹淌,所以主要看ReactActivityDelegate的實現河绽。

看看其代理的onCreate方法的實現:

  protected void onCreate(Bundle savedInstanceState) {
    if (mMainComponentName != null) {
      loadApp(mMainComponentName);
    }
    mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
  }

  protected void loadApp(String appKey) {
    if (mReactRootView != null) {
      throw new IllegalStateException("Cannot loadApp while app is already running.");
    }
    //1.
    mReactRootView = createRootView();
    //2.
    mReactRootView.startReactApplication(
      getReactNativeHost().getReactInstanceManager(),
      appKey,
      getLaunchOptions());
    //3/
    getPlainActivity().setContentView(mReactRootView);
  }

程序運行到這里和普通程序一樣,創(chuàng)建一個View唉窃,然后setContentView耙饰。多了第2步。而第2步就是啟動react-native.
所以重點看一下mReactRootView.startReactApplication()這個方法做了啥纹份?

1.創(chuàng)建ReactInstanceManager

這個函數需第一個參數是ReactInstanceManager苟跪,這個是通過getReactNativeHost().getReactInstanceManager()來獲取的,
getReactNativeHost()正是MainApplication里面返回的值蔓涧。

getReactInstanceManager()第一次調用會創(chuàng)建,會調用createReactInstanceManager(),這個方法跟啟動息息相關件已,所以也要重點看一下實現。

  // ReactNativeHost.java
  protected ReactInstanceManager createReactInstanceManager() {
    ReactInstanceManagerBuilder builder = ReactInstanceManager.builder()
      .setApplication(mApplication)
      .setJSMainModulePath(getJSMainModuleName())
      .setUseDeveloperSupport(getUseDeveloperSupport())
      .setRedBoxHandler(getRedBoxHandler())
      .setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())
      .setUIImplementationProvider(getUIImplementationProvider())
      .setInitialLifecycleState(LifecycleState.BEFORE_CREATE);

    for (ReactPackage reactPackage : getPackages()) {
      builder.addPackage(reactPackage);
    }

    String jsBundleFile = getJSBundleFile();
    if (jsBundleFile != null) {
      builder.setJSBundleFile(jsBundleFile);
    } else {
      builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName()));
    }
    return builder.build();
  }

這個方法將ReactNativeHost得到的Native的配置全部設置給ReactInstanceManager元暴,然后調用build()篷扩。
build當中會調用ReactInstanceManager構造函數,所以代碼轉到ReactInstanceManager構造函數中

  /* package */ ReactInstanceManager(
      Context applicationContext,
      @Nullable Activity currentActivity,
      @Nullable DefaultHardwareBackBtnHandler defaultHardwareBackBtnHandler,
      JavaScriptExecutorFactory javaScriptExecutorFactory,
      @Nullable JSBundleLoader bundleLoader,
      @Nullable String jsMainModulePath,
      List<ReactPackage> packages,
      boolean useDeveloperSupport,
      @Nullable NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener,
      LifecycleState initialLifecycleState,
      UIImplementationProvider uiImplementationProvider,
      NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler,
      @Nullable RedBoxHandler redBoxHandler,
      boolean lazyNativeModulesEnabled,
      boolean lazyViewManagersEnabled,
      boolean delayViewManagerClassLoadsEnabled,
      @Nullable DevBundleDownloadListener devBundleDownloadListener,
      int minNumShakes,
      int minTimeLeftInFrameForNonBatchedOperationMs) {
    Log.d(ReactConstants.TAG, "ReactInstanceManager.ctor()");
    initializeSoLoaderIfNecessary(applicationContext);

    DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(applicationContext);

    mApplicationContext = applicationContext;
    mCurrentActivity = currentActivity;
    mDefaultBackButtonImpl = defaultHardwareBackBtnHandler;
    mJavaScriptExecutorFactory = javaScriptExecutorFactory;
    mBundleLoader = bundleLoader;
    mJSMainModulePath = jsMainModulePath;
    mPackages = new ArrayList<>();
    mInitFunctions = new ArrayList<>();
    mUseDeveloperSupport = useDeveloperSupport;
    mDevSupportManager =
        DevSupportManagerFactory.create(
            applicationContext,
            createDevHelperInterface(),
            mJSMainModulePath,
            useDeveloperSupport,
            redBoxHandler,
            devBundleDownloadListener,
            minNumShakes);
    mBridgeIdleDebugListener = bridgeIdleDebugListener;
    mLifecycleState = initialLifecycleState;
    mMemoryPressureRouter = new MemoryPressureRouter(applicationContext);
    mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
    mLazyNativeModulesEnabled = lazyNativeModulesEnabled;
    mDelayViewManagerClassLoadsEnabled = delayViewManagerClassLoadsEnabled;
    synchronized (mPackages) {
      PrinterHolder.getPrinter()
          .logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: Use Split Packages");
      mPackages.add(
          new CoreModulesPackage(
              this,
              new DefaultHardwareBackBtnHandler() {
                @Override
                public void invokeDefaultOnBackPressed() {
                  ReactInstanceManager.this.invokeDefaultOnBackPressed();
                }
              },
              uiImplementationProvider,
              lazyViewManagersEnabled,
              minTimeLeftInFrameForNonBatchedOperationMs));
      if (mUseDeveloperSupport) {
        mPackages.add(new DebugCorePackage());
      }
      mPackages.addAll(packages);
    }

    // Instantiate ReactChoreographer in UI thread.
    ReactChoreographer.initialize();
    if (mUseDeveloperSupport) {
      mDevSupportManager.startInspector();
    }
  }

一坨參數茉盏,我們尋找啟動所以沒必要研究個參數的構建鉴未,只要知道ReactInstanceManager在初次調用startReactApplication()的時候創(chuàng)建了就差不多了

2.創(chuàng)建ReactContext

因為主要看啟動所以這里知道啟動了一個ReactContext就夠了

 ...
 
 if (!mReactInstanceManager.hasStartedCreatingInitialContext()) {
    mReactInstanceManager.createReactContextInBackground();
  }
  
 ...
3.將ReactRootView綁定到ReactInstanceManager

綁定之后,最終會調用rootView的runApplication()

  private void attachRootViewToInstance(
      final ReactRootView rootView,
      CatalystInstance catalystInstance) {
      
    ....
    
    UIManagerModule uiManagerModule = catalystInstance.getNativeModule(UIManagerModule.class);
    final int rootTag = uiManagerModule.addRootView(rootView);
    rootView.setRootViewTag(rootTag);
    rootView.runApplication();
 
    .....
  }
  /* package */ void runApplication() {
 
    ......
 
      CatalystInstance catalystInstance = reactContext.getCatalystInstance();

      WritableNativeMap appParams = new WritableNativeMap();
      appParams.putDouble("rootTag", getRootViewTag());
      @Nullable Bundle appProperties = getAppProperties();
      if (appProperties != null) {
        appParams.putMap("initialProps", Arguments.fromBundle(appProperties));
      }

      mShouldLogContentAppeared = true;

      String jsAppModuleName = getJSModuleName();
      catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);

    ......
  }

runApplication最重要的就是

catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);

這個了鸠姨,這個會通過一個動態(tài)代理的方式構建出一個AppRegistry的代理類铜秆,然后代理類執(zhí)行的runApplication

  public synchronized <T extends JavaScriptModule> T getJavaScriptModule(
      CatalystInstance instance,
      Class<T> moduleInterface) {
    JavaScriptModule module = mModuleInstances.get(moduleInterface);
    if (module != null) {
      return (T) module;
    }

    JavaScriptModule interfaceProxy = (JavaScriptModule) Proxy.newProxyInstance(
        moduleInterface.getClassLoader(),
        new Class[]{moduleInterface},
        new JavaScriptModuleInvocationHandler(instance, moduleInterface));
   .....
  }

然后調用轉到JavaScriptModuleInvocationHandler的invoke當中,最終會調用CatalystInstanceImpl的call()方法

    void call(CatalystInstanceImpl catalystInstance) {
      NativeArray arguments = mArguments != null ? mArguments : new WritableNativeArray();
      catalystInstance.jniCallJSFunction(mModule, mMethod, arguments);
    }

mModule就是js的AppRegistry 讶迁,mMethod 就是 runApplication 连茧,方法會調用js模塊中 AppRegistry的 runApplication。
到此Native的執(zhí)行完畢巍糯。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末啸驯,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子祟峦,更是在濱河造成了極大的恐慌坯汤,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搀愧,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機咱筛,發(fā)現死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門搓幌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人迅箩,你說我怎么就攤上這事溉愁。” “怎么了饲趋?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵拐揭,是天一觀的道長。 經常有香客問我奕塑,道長堂污,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任龄砰,我火速辦了婚禮盟猖,結果婚禮上,老公的妹妹穿的比我還像新娘换棚。我一直安慰自己式镐,他們只是感情好,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布固蚤。 她就那樣靜靜地躺著娘汞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪夕玩。 梳的紋絲不亂的頭發(fā)上你弦,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機與錄音风秤,去河邊找鬼鳖目。 笑死,一個胖子當著我的面吹牛缤弦,可吹牛的內容都是我干的领迈。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼碍沐,長吁一口氣:“原來是場噩夢啊……” “哼狸捅!你這毒婦竟也來了?” 一聲冷哼從身側響起累提,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤尘喝,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后斋陪,有當地人在樹林里發(fā)現了一具尸體朽褪,經...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡置吓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了缔赠。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片衍锚。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖嗤堰,靈堂內的尸體忽然破棺而出戴质,到底是詐尸還是另有隱情,我是刑警寧澤踢匣,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布告匠,位于F島的核電站,受9級特大地震影響离唬,放射性物質發(fā)生泄漏后专。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一男娄、第九天 我趴在偏房一處隱蔽的房頂上張望行贪。 院中可真熱鬧,春花似錦模闲、人聲如沸建瘫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽啰脚。三九已至,卻和暖如春实夹,著一層夾襖步出監(jiān)牢的瞬間橄浓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工亮航, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留荸实,地道東北人。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓缴淋,卻偏偏與公主長得像准给,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子重抖,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內容