.map reactnative

2018-11-09 16:09:24 ahou2468 阅读数 1204

目录

 

1.初始创建目录结构说明

2.编辑React Native中的JS代码

3.编写IOS/Android原生代码

4.如何添加第三方react native npm源码库

4.1仅仅涉及React Native开发

4.2涉及React Native和IOS或者Android混合开发

5.第三方代码添加到libs包中

6.项目实际开发的目录结构


1.初始创建目录结构说明

开发项目之前首先了解一下项目的目录结构,方便后期开发;

React Native是建立在Android和IOS的SDK之上的SDK,React Native主要包含三部分:

a.Android的原生工程;

b.ios的原生工程;

c.React Native相关;

HelloWorld
          |-- android
          |-- ios
          |-- node_modules
          |-- package.json
          |-- index.js  

目录结构各分部简单介绍:

android:项目的Android的原生工程;

ios:        项目的IOS的原生工程;

node_modules:这个文件夹主要存放根据package.json文件声明的依赖,通过公网下载下来的第三方react native npm包源代码;(备注:在初始化创建项目时此目录会自动创建并下载第三方react native npm包源代码)

package.json:React Native是基于javasript开发的语言,使用npm做为包管理,这个文件就是npm的包管理的文件,主要配置我们依赖的第三方包;

index.js:这个文件是IOS和Android在相应设备上打包运行的入口文件;(备注:早起React Native项目应该是index.ios.js和index.android.js两个单独的入口文件)

2.编辑React Native中的JS代码

项目编辑之前都需要类似像Java一样做分包的创建,简单说明一下我们正式项目的目录结构

HelloWorld
          |-- android
          |-- ios
          |-- node_modules
          |-- package.json
          |-- index.js  
          |-- img
          |-- public
          |-- scene

我在原有的基础上添加了三个目录分别img,public,scene三个目录;

img:存放界面要显示的png图片;

public:存放工具js,网络请求js的封装,数据存储js等相关操作的js;(备注:可以在public中创建分类目录,public/net、public/net、public/datastorage等)

scene:存放项目的JS组件(界面);(备注:可以在scene目录下创建不同功能模块的目录,例如scene/draw,scene/user,scene/home等二级三级目录)

3.编写IOS/Android原生代码

React Native实际上不能完全替代IOS或者Android原生的功能,那么就需要我们在android或者ios原生的API实现实现我们的需求;

React Native支持只用ReactNative单独开发,也可以RN、IOS或者Android原生混合开发;

HelloWorld/android:android原生开发;(备注:实际使用参考RN中文网https://reactnative.cn/docs/native-modules-android/

HelloWorld/ios:IOS原生开发;备注:实际使用参考RN中文网https://reactnative.cn/docs/native-modules-ios/

scene:React Native开发;

4.如何添加第三方react native npm源码库

4.1仅仅涉及React Native开发

首先打开HelloWorld/package.json文件,找到以后depencencies标签,添加第三方包react-native-modal并指定版本版本,第一种WebStorm会自动提示运行npm install安装第三方包,点击Run 'npm install'即可;第二种当然还可以进入HellWorld目录执行执行npm install <package_name> --save命令安装第三方包,例如npm install react-native-modal --save;

 "dependencies": {
    "react": "16.6.0-alpha.8af6728",
    "react-native": "0.57.4",
    "react-native-modal": "^6.5.0"
  },

执行网npm install命令以后,我们会发现node_modules下多了react-native-modal目录,react-native-modal目录主要存放模态框的源码,下面就可以在代码中引用模态框,如下:

import Modal from "react-native-modal";

4.2涉及React Native和IOS或者Android混合开发

 

例如React Native需要调用百度地图第三方库react-native-baidu-map,添加react-native-baidu-map以后是无法调用百度地图的;

 "dependencies": {
    "react": "16.6.0-alpha.8af6728",
    "react-native": "0.57.4",
    "react-native-modal": "^6.5.0",
    "react-native-baidu-map": "^0.6.0",
  },

我还需要在Android原生工程或者IOS原生工程中进行配置,在AndroidManifest.xml添加定位权限操作需要要在原生工程中添加其他配置参考https://www.npmjs.com/package/react-native-baidu-map第三方地址,每个第三方涉及第三方的配置都会有readme这个一定要看,一般使用 Manual install 配置方式比较保险,automatic install 有可能会漏掉一些配置;

5.第三方代码添加到libs包中

由于加入到node_modules第三方库都是从公网上下载下来的,第三库提供的功能可能不能满足我们的需求,那么我们怎么保证修改的代码换一个环境仍然可以正常使用呢,那么我们就需要HelloWorld目录新建libs目录,libs目录来专门放置这些第三方 react native npm 包的源代码;

例如react-native-baidu-map源代码库我们可以迁移到libs目录;

6.项目实际开发的目录结构

HelloWorld
          |-- android
          |-- ios
          |-- node_modules
          |-- package.json
          |-- index.js  
          |-- img
          |-- public
          |-- scene
          |-- libs

android:Android原生工程目录;

ios:IOS原生工程目录;

package.json:React Native是基于javasript开发的语言,使用npm做为包管理,这个文件就是npm的包管理的文件,主要配置我们依赖的第三方包;

index.js:这个文件是IOS和Android在相应设备上打包运行的入口文件;(备注:早起React Native项目应该是index.ios.js和index.android.js两个单独的入口文件)

img:存放界面要显示的png图片;

public:存放工具js,网络请求js的封装,数据存储js等相关操作的js;(备注:可以在public中创建分类目录,public/net、public/net、public/datastorage等)

scene:存放项目的JS组件(界面);(备注:可以在scene目录下创建不同功能模块的目录,例如scene/draw,scene/user,scene/home等二级三级目录)

libs:手动进入npm第三方库源码,方便以后修改;

参考:

https://github.com/fushang318/react-native-demo/wiki/react-native-工程目录结构说明

https://reactnative.cn/docs

2018-08-02 17:50:29 DZh_Ming 阅读数 5801

map方法的作用不难理解,“映射”嘛,也就是原数组被“映射”成对应新数组。下面这个例子是数值项求平方:


var data = [1, 2, 3, 4];

var arrayOfSquares = data.map(function (item) {
  return item * item;
});

alert(arrayOfSquares); // 1, 4, 9, 16
callback需要有return值,如果没有,就像下面这样:
var data = [1, 2, 3, 4];
var arrayOfSquares = data.map(function() {});

arrayOfSquares.forEach(console.log);

结果如下图,可以看到,数组所有项都被映射成了undefined:

在实际使用的时候,我们可以利用map方法方便获得对象数组中的特定属性值们。例如下面这个例子(之后的兼容demo也是该例子):

var users = [
  {name: "张含韵", "email": "zhang@email.com"},
  {name: "江一燕",   "email": "jiang@email.com"},
  {name: "李小璐",  "email": "li@email.com"}
];

var emails = users.map(function (user) { return user.email; });

console.log(emails.join(", ")); // zhang@email.com, jiang@email.com, li@email.com

2020-04-15 23:35:13 FrewenWong 阅读数 92

文章参考:https://github.com/sucese/react-native/blob/master/doc/ReactNative%E6%BA%90%E7%A0%81%E7%AF%87/3ReactNative%E6%BA%90%E7%A0%81%E7%AF%87%EF%BC%9A%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B.md

文章参考:https://www.jianshu.com/p/baff68f85d41

创建ReactNativeHost

ReactNative的启动流程,我们首先看Application中的代码,实例化ReactNativeHost。ReactNativeHost主要的工作就是创建了ReactInstanceManager,它将一些信息传递给了ReactInstanceManager。同时,我们看一下ReactNativeHost的提供的方法。

public abstract class ReactNativeHost {
   
      protected ReactInstanceManager createReactInstanceManager() {
        ReactInstanceManagerBuilder builder = ReactInstanceManager.builder()
          //应用上下文
          .setApplication(mApplication)
          //JSMainModuleP相当于应用首页的js Bundle,可以传递url从服务器拉取js Bundle
          //当然这个只在dev模式下可以使用
          .setJSMainModulePath(getJSMainModuleName())
          //是否开启dev模式
          .setUseDeveloperSupport(getUseDeveloperSupport())
          //红盒的回调
          .setRedBoxHandler(getRedBoxHandler())
          //自定义UI实现机制,这个我们一般用不到
          .setUIImplementationProvider(getUIImplementationProvider())
          .setInitialLifecycleState(LifecycleState.BEFORE_CREATE);
    
        //添加ReactPackage
        for (ReactPackage reactPackage : getPackages()) {
          builder.addPackage(reactPackage);
        }
    
        //获取js Bundle的加载路径
        String jsBundleFile = getJSBundleFile();
        if (jsBundleFile != null) {
          builder.setJSBundleFile(jsBundleFile);
        } else {
          builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName()));
        }
        return builder.build();
      }
}

下面是ReactNativeHost提供的一些方法:

protected @Nullable RedBoxHandler getRedBoxHandler();
protected @Nullable JavaScriptExecutorFactory getJavaScriptExecutorFactory();
protected final Application getApplication();
protected UIImplementationProvider getUIImplementationProvider();

实例化ReactActivityDelegate:

启动ReactActivity的子类实例,在这个Activty的启动流程中,正式开始我们ReactNative启动和加载流程。
我们先来分析一下ReactActivityDelegate。我么可以看到ReactActivityDelegate的一些提供的方法。就知道这个类的一些职责。他主要就是Activity的宿主的一些生命周期的委托调用。也就是所有ReactNative和宿主Activity的关联都是通过这个类类简历联系的。

当然我们也看到。其实所有的生命周期的方法。这个类要么委托给ReactDelegate。要么就是直接ReactInstanceManager进行处理。所以这个类的职责也是非常简单的。

可以说ReactNative和她的宿主Activity达到了很好的解耦。

public abstract class ReactActivity extends AppCompatActivity
    implements DefaultHardwareBackBtnHandler, PermissionAwareActivity {

  private final ReactActivityDelegate mDelegate;

  protected ReactActivity() {
    mDelegate = createReactActivityDelegate();
  }

  /**
   * Returns the name of the main component registered from JavaScript. This is used to schedule
   * rendering of the component. e.g. "MoviesApp"
   */
  protected @Nullable String getMainComponentName() {
    return null;
  }

  /** Called at construction time, override if you have a custom delegate implementation. */
  protected ReactActivityDelegate createReactActivityDelegate() {
    return new ReactActivityDelegate(this, getMainComponentName());
  }
  .......
}

这个类很简单,就是实例化的一个Activity的委托对象。然后所有的生命周期调用全部使用ReactActivityDelegate的代理对象完成。

那么下面,我们看一下这个类的实现。

public ReactActivityDelegate(ReactActivity activity, @Nullable String mainComponentName) {
    Log.d(TAG, "第二步:FMsg: 实例化ReactActivityDelegate called with: activity = [" + activity + "], mainComponentName = [" + mainComponentName + "]");
    mActivity = activity;
    mMainComponentName = mainComponentName;
  }

我们看一下。Activity的onCreate的方法的代理实现。

实例化ReactDelegate

protected void onCreate(Bundle savedInstanceState) {
    String mainComponentName = getMainComponentName();
    mReactDelegate =
        new ReactDelegate(
            getPlainActivity(), getReactNativeHost(), mainComponentName, getLaunchOptions()) {
          @Override
          protected ReactRootView createRootView() {
            return ReactActivityDelegate.this.createRootView();
          }
        };
    //mMainComponentName就是上面ReactActivity.getMainComponentName()返回的组件名    
    if (mMainComponentName != null) {
      //载入app页面
      loadApp(mainComponentName);
    }
  }

这个方法一个,实例化ReactDelegate对象。二是调用loadApp的方法。

我们来看一下ReactDelegate的这个对象。他的职责到底是什么呢??

protected void loadApp(String appKey) {
    mReactDelegate.loadApp(appKey);
    getPlainActivity().setContentView(mReactDelegate.getReactRootView());
  }

这个方法很简单。还是调用了ReactDelegate的loadApp方法。至此位置ReactActivityDelegate的启动流程中的职责也就告一段落。下面我们看一下ReactDelegate里面的loadApp

  public void loadApp(String appKey) {
    if (mReactRootView != null) {
      throw new IllegalStateException("Cannot loadApp while app is already running.");
    }
    //创建ReactRootView作为根视图,它本质上是一个FrameLayout
    mReactRootView = createRootView();、
    //启动RN应用.这个地方我们要注意下。ReactInstanceManager就是从这个地方开始实例化的。
    mReactRootView.startReactApplication(
        getReactNativeHost().getReactInstanceManager(), appKey, mLaunchOptions);
  }

最终这个方法是调用到ReactRootView。这个View我们知道,其实就是我们通过setContentView设置给Activity宿主的FameLayout

实例化ReactInstanceManager

我们可以从代码中看到,在startReactApplication的时候,我们通过ReactNativeHost的实例化对象来获取ReactInstanceManager

 /** Get the current {@link ReactInstanceManager} instance, or create one. */
  public ReactInstanceManager getReactInstanceManager() {
    if (mReactInstanceManager == null) {
      ReactMarker.logMarker(ReactMarkerConstants.GET_REACT_INSTANCE_MANAGER_START);
      mReactInstanceManager = createReactInstanceManager();
      ReactMarker.logMarker(ReactMarkerConstants.GET_REACT_INSTANCE_MANAGER_END);
    }
    return mReactInstanceManager;
  }
  
  
  protected ReactInstanceManager createReactInstanceManager() {
    ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_START);
    Log.d(TAG, "FMsg:第五步:createReactInstanceManager() called");
    ReactInstanceManagerBuilder builder =
        ReactInstanceManager.builder()
            .setApplication(mApplication)
             // 设置JSMain的根路径地址。也就是index.js  //"index.android"
            .setJSMainModulePath(getJSMainModuleName())
            .setUseDeveloperSupport(getUseDeveloperSupport())
            //红盒的回调
            .setRedBoxHandler(getRedBoxHandler())
            // 获取JS执行引擎的工作累的方法。默认是JSC。当然我们也可以自定义设置成V8的引擎
            // 如果需要自定义设置,那么Application中重写这个方法
            .setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())
             //自定义UI实现机制,这个我们一般用不到
            .setUIImplementationProvider(getUIImplementationProvider())
            .setJSIModulesPackage(getJSIModulePackage())
            .setInitialLifecycleState(LifecycleState.BEFORE_CREATE);
    // 类实例化的作用就是传递给ReactInstanceManager所有的Packages
    Log.i(TAG, "FMsg:第五步:createReactInstanceManager: addPackage  size = " + getPackages().size());
    // 这个使我们Application实例化的时候,我们提供的ReactPackage
    for (ReactPackage reactPackage : getPackages()) {
      builder.addPackage(reactPackage);
    }

    String jsBundleFile = getJSBundleFile();
    Log.i(TAG, "FMsg:第五步:createReactInstanceManager: jsBundleFile = "+jsBundleFile);
    if (jsBundleFile != null) {
      builder.setJSBundleFile(jsBundleFile);
    } else {
      builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName()));
    }
    // 这个建造者模式,可以好好分析一下。里面有很多的默认参数
    ReactInstanceManager reactInstanceManager = builder.build();
    ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_END);
    return reactInstanceManager;
  }

 

其实从这个地方。ReactNativeHost的历史使命就完成了。所有我们复写的他的提供方法都是在这个地方传递给ReactInstance的构造化实例对象。

下面,我们来看一下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,
      @Nullable UIImplementationProvider mUIImplementationProvider,
      NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler,
      @Nullable RedBoxHandler redBoxHandler,
      boolean lazyViewManagersEnabled,
      @Nullable DevBundleDownloadListener devBundleDownloadListener,
      int minNumShakes,
      // 这个参数也比较重要,这个参数就是ReactNative的刷新帧的频率。默认-1.表示直接使用Android的刷新帧频率
      int minTimeLeftInFrameForNonBatchedOperationMs,
      @Nullable JSIModulePackage jsiModulePackage,
      @Nullable Map<String, RequestHandler> customPackagerCommandHandlers) {
    Log.d(ReactConstants.TAG, "ReactInstanceManager.ctor()");
    Log.d(TAG, "FMsg:第五步:ReactInstanceManager() called with: currentActivity = [" + currentActivity + "], defaultHardwareBackBtnHandler = [" + defaultHardwareBackBtnHandler + "], javaScriptExecutorFactory = [" + javaScriptExecutorFactory + "], bundleLoader = [" + bundleLoader + "], jsMainModulePath = [" + jsMainModulePath + "], packages = [" + packages + "], useDeveloperSupport = [" + useDeveloperSupport + "], bridgeIdleDebugListener = [" + bridgeIdleDebugListener + "], initialLifecycleState = [" + initialLifecycleState + "], mUIImplementationProvider = [" + mUIImplementationProvider + "], nativeModuleCallExceptionHandler = [" + nativeModuleCallExceptionHandler + "], redBoxHandler = [" + redBoxHandler + "], lazyViewManagersEnabled = [" + lazyViewManagersEnabled + "], devBundleDownloadListener = [" + devBundleDownloadListener + "], minNumShakes = [" + minNumShakes + "], minTimeLeftInFrameForNonBatchedOperationMs = [" + minTimeLeftInFrameForNonBatchedOperationMs + "], jsiModulePackage = [" + jsiModulePackage + "], customPackagerCommandHandlers = [" + customPackagerCommandHandlers + "]");
    initializeSoLoaderIfNecessary(applicationContext);

    DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(applicationContext);

    mApplicationContext = applicationContext;
    mCurrentActivity = currentActivity;
    mDefaultBackButtonImpl = defaultHardwareBackBtnHandler;
    // 其实默认传入的null  如果我们想使用其他JS引擎,比如V8.我们可以在这里面进行传入
    mJavaScriptExecutorFactory = javaScriptExecutorFactory;
    mBundleLoader = bundleLoader;
    mJSMainModulePath = jsMainModulePath;
    mPackages = new ArrayList<>();
    mUseDeveloperSupport = useDeveloperSupport;
    Systrace.beginSection(
        Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ReactInstanceManager.initDevSupportManager");
    mDevSupportManager =
        DevSupportManagerFactory.create(
            applicationContext,
            createDevHelperInterface(),
            mJSMainModulePath,
            useDeveloperSupport,
            redBoxHandler,
            devBundleDownloadListener,
            minNumShakes,
            customPackagerCommandHandlers);
    Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
    mBridgeIdleDebugListener = bridgeIdleDebugListener;
    mLifecycleState = initialLifecycleState;
    mMemoryPressureRouter = new MemoryPressureRouter(applicationContext);
    mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;

    /// 这个地方就是添加ReactPackage
    synchronized (mPackages) {
      PrinterHolder.getPrinter()
          .logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: Use Split Packages");
      // 这个方法很重要,这个方法我们会将系统内置的那些CoreModulesPackage添加进去
      // AndroidInfoModule.class,
      // DeviceEventManagerModule.class,
      // DeviceInfoModule.class,
      // DevSettingsModule.class,
      // ExceptionsManagerModule.class,
      // HeadlessJsTaskSupportModule.class,
      // SourceCodeModule.class,
      // Timing.class,
      // UIManagerModule.class
      mPackages.add(
          new CoreModulesPackage(
              this,
              new DefaultHardwareBackBtnHandler() {
                @Override
                public void invokeDefaultOnBackPressed() {
                  ReactInstanceManager.this.invokeDefaultOnBackPressed();
                }
              },
              mUIImplementationProvider,
              lazyViewManagersEnabled,
              minTimeLeftInFrameForNonBatchedOperationMs));
      if (mUseDeveloperSupport) {
        mPackages.add(new DebugCorePackage());
      }
      mPackages.addAll(packages);
    }
    mJSIModulePackage = jsiModulePackage;

    // Instantiate ReactChoreographer in UI thread.
    // 这个就是实例化Android的序列帧的监听对象
    ReactChoreographer.initialize();
    if (mUseDeveloperSupport) {
      mDevSupportManager.startInspector();
    }
  }

从ReactInstanceManager的构造函数,我们可以看到。所有ReactNative的启动的初始化资源基本都已经准备完毕。所以startReactApplication的方法。我们必须要传入ReactInstanceManager实例化对象。

其实通过查看ReactInstance的类的内容,我们可以看到这个类的方法其实也是比较简单的。他的关于启动流程最大的一个作用就是创建ReactContext。那么这个创建ReactContext是什么开始的呢?

我们来继续看ReactRootView的startReactApplication方法。

startReactApplication

  @ThreadConfined(UI)
  public void startReactApplication(
      ReactInstanceManager reactInstanceManager,
      String moduleName,
      @Nullable Bundle initialProperties,
      @Nullable String initialUITemplate) {
    Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "startReactApplication");
    try {
      // 线程检查
      UiThreadUtil.assertOnUiThread();

      // TODO(6788889): Use POJO instead of bundle here, apparently we can't just use WritableMap
      // here as it may be deallocated in native after passing via JNI bridge, but we want to reuse
      // it in the case of re-creating the catalyst instance
      Assertions.assertCondition(
          mReactInstanceManager == null,
          "This root view has already been attached to a catalyst instance manager");

      mReactInstanceManager = reactInstanceManager;
      mJSModuleName = moduleName;
      mAppProperties = initialProperties;
      mInitialUITemplate = initialUITemplate;

      if (mUseSurface) {
        // TODO initialize surface here
      }
      //创建RN上下文上下文对象
      mReactInstanceManager.createReactContextInBackground();
      //attachToReactInstanceManager 调用的是mReactInstanceManager.attachRootView(this)
      attachToReactInstanceManager();

    } finally {
      Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
    }
  }

这个方法比较深,我们可以一步步往下看。进入到这个方法,就进入到ReactInstance的核心功能。也是ReactNative启动的核心流程。也是最重要的流程中。createReactContext的创建流程。

@ThreadConfined(UI)
  public void createReactContextInBackground() {
    Log.d(ReactConstants.TAG, "ReactInstanceManager.createReactContextInBackground()");
    Log.d(TAG, "FMsg:第六步:ReactRootView开始创建ReactContext createReactContextInBackground() called");
    UiThreadUtil
        .assertOnUiThread(); // Assert before setting mHasStartedCreatingInitialContext = true
    if (!mHasStartedCreatingInitialContext) {
      mHasStartedCreatingInitialContext = true;
      recreateReactContextInBackgroundInner();
    }
  }
  
  
   @ThreadConfined(UI)
  private void recreateReactContextInBackgroundInner() {
    Log.d(ReactConstants.TAG, "ReactInstanceManager.recreateReactContextInBackgroundInner()");
    Log.d(TAG, "FMsg:第六步:调用内部方法recreateReactContextInBackgroundInner() called");
    PrinterHolder.getPrinter()
        .logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: recreateReactContextInBackground");
    UiThreadUtil.assertOnUiThread();
    // 调试相关的逻辑,咱们暂时忽略
    if (mUseDeveloperSupport && mJSMainModulePath != null) {
      final DeveloperSettings devSettings = mDevSupportManager.getDevSettings();

      if (!Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JS_VM_CALLS)) {
        if (mBundleLoader == null) {
          mDevSupportManager.handleReloadJS();
        } else {
          mDevSupportManager.isPackagerRunning(
              new PackagerStatusCallback() {
                @Override
                public void onPackagerStatusFetched(final boolean packagerIsRunning) {
                  UiThreadUtil.runOnUiThread(
                      new Runnable() {
                        @Override
                        public void run() {
                          if (packagerIsRunning) {
                            mDevSupportManager.handleReloadJS();
                          } else if (mDevSupportManager.hasUpToDateJSBundleInCache()
                              && !devSettings.isRemoteJSDebugEnabled()) {
                            // If there is a up-to-date bundle downloaded from server,
                            // with remote JS debugging disabled, always use that.
                            onJSBundleLoadedFromServer(null);
                          } else {
                            // If dev server is down, disable the remote JS debugging.
                            devSettings.setRemoteJSDebugEnabled(false);
                            recreateReactContextInBackgroundFromBundleLoader();
                          }
                        }
                      });
                }
              });
        }
        return;
      }
    }

    recreateReactContextInBackgroundFromBundleLoader();
  }
  
  
   @ThreadConfined(UI)
  private void recreateReactContextInBackgroundFromBundleLoader() {
    Log.d(
        ReactConstants.TAG,
        "ReactInstanceManager.recreateReactContextInBackgroundFromBundleLoader()");
    Log.d(TAG, "FMsg:第六步:线上环境来将会使用后台任务创建ReactContext recreateReactContextInBackgroundFromBundleLoader() called");
    PrinterHolder.getPrinter()
        .logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: load from BundleLoader");
    recreateReactContextInBackground(mJavaScriptExecutorFactory, mBundleLoader);
  }
  
  
    @ThreadConfined(UI)
  private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams) {
    Log.d(ReactConstants.TAG, "ReactInstanceManager.runCreateReactContextOnNewThread()");
    Log.d(TAG, "FMsg:第六步:runCreateReactContextOnNewThread() called with: initParams = [" + initParams + "]");
    UiThreadUtil.assertOnUiThread();
    synchronized (mAttachedReactRoots) {
      synchronized (mReactContextLock) {
        // 生命周期的回收,主要是针对可能会造成的多次初始化RN环境的
        if (mCurrentReactContext != null) {
          tearDownReactContext(mCurrentReactContext);
          mCurrentReactContext = null;
        }
      }
    }

    mCreateReactContextThread =
        new Thread(
            null,
            new Runnable() {
              @Override
              public void run() {
                ReactMarker.logMarker(REACT_CONTEXT_THREAD_END);
                synchronized (ReactInstanceManager.this.mHasStartedDestroying) {
                  while (ReactInstanceManager.this.mHasStartedDestroying) {
                    try {
                      ReactInstanceManager.this.mHasStartedDestroying.wait();
                    } catch (InterruptedException e) {
                      continue;
                    }
                  }
                }
                // As destroy() may have run and set this to false, ensure that it is true before we
                // create
                mHasStartedCreatingInitialContext = true;

                try {
                  Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
                  ReactMarker.logMarker(VM_INIT);
                  Log.i(TAG, "FMsg:第六步:runCreateReactContextOnNewThread run: " + Thread.currentThread().getName());
                  final ReactApplicationContext reactApplicationContext =
                      createReactContext(
                          initParams.getJsExecutorFactory().create(),
                          initParams.getJsBundleLoader());

                  mCreateReactContextThread = null;
                  ReactMarker.logMarker(PRE_SETUP_REACT_CONTEXT_START);

                  // 这个地方也是一个保护机制,我们暂时不需要关注
                  final Runnable maybeRecreateReactContextRunnable =
                      new Runnable() {
                        @Override
                        public void run() {
                          if (mPendingReactContextInitParams != null) {
                            runCreateReactContextOnNewThread(mPendingReactContextInitParams);
                            mPendingReactContextInitParams = null;
                          }
                        }
                      };
                  Runnable setupReactContextRunnable =
                      new Runnable() {
                        @Override
                        public void run() {
                          try {
                            setupReactContext(reactApplicationContext);
                          } catch (Exception e) {
                            mDevSupportManager.handleException(e);
                          }
                        }
                      };

                  reactApplicationContext.runOnNativeModulesQueueThread(setupReactContextRunnable);
                  UiThreadUtil.runOnUiThread(maybeRecreateReactContextRunnable);
                } catch (Exception e) {
                  mDevSupportManager.handleException(e);
                }
              }
            },
            "create_react_context");
    ReactMarker.logMarker(REACT_CONTEXT_THREAD_START);
    mCreateReactContextThread.start();
  }

这个地方就是我们比较重要的创建ReactContext对象的逻辑。

   /** @return instance of {@link ReactContext} configured a {@link CatalystInstance} set */
  private ReactApplicationContext createReactContext(
      JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader) {
    Log.d(TAG, "FMsg:第六步:ReactInstanceManager.createReactContext " + Thread.currentThread().getName());
    Log.d(TAG, "FMsg:第六步:createReactContext() called with: jsExecutor = [" + jsExecutor + "], jsBundleLoader = [" + jsBundleLoader + "]");
    ReactMarker.logMarker(CREATE_REACT_CONTEXT_START, jsExecutor.getName());
    // 这个地方就进行了实例化reactContext
    // ReactApplicationContext extends ReactContext extends ContextWrapper
    // 构造函数传入的是Context。 eactApplicationContext是ReactContext的包装类。
    final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);

    // 这个就是NativeModuleCallExceptionHandler.异常捕获器
    NativeModuleCallExceptionHandler exceptionHandler =
        mNativeModuleCallExceptionHandler != null
            ? mNativeModuleCallExceptionHandler
            : mDevSupportManager;
    reactContext.setNativeModuleCallExceptionHandler(exceptionHandler);

    // 创建JavaModule注册表Builder,用来创建JavaModule注册表,JavaModule注册表将所有的JavaModule注册到CatalystInstance中。
    NativeModuleRegistry nativeModuleRegistry = processPackages(reactContext, mPackages, false);
    // 最最重要的一个对象,催化器实例对象
    // jsExecutor、nativeModuleRegistry、nativeModuleRegistry等各种参数处理好之后,开始构建CatalystInstanceImpl实例。
    CatalystInstanceImpl.Builder catalystInstanceBuilder =
        new CatalystInstanceImpl.Builder()
                // 设置ReactNative的消息队列的配置数据
            .setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
                // 通过JS执行器工厂实例化的JS线程执行器
            .setJSExecutor(jsExecutor)
            .setRegistry(nativeModuleRegistry)
            .setJSBundleLoader(jsBundleLoader)
            .setNativeModuleCallExceptionHandler(exceptionHandler);

    ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_START);
    // CREATE_CATALYST_INSTANCE_END is in JSCExecutor.cpp
    Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstance");
    final CatalystInstance catalystInstance;
    try {
      // 没什么好说的。空值判断。但是催化器的构造函数我们需要研究一下。
      // 里面针对消息队列的线程进行初始化
      catalystInstance = catalystInstanceBuilder.build();
    } finally {
      Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
      ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_END);
    }

    // 关联ReacContext与CatalystInstance实例化
    // 解析上面实例化的是三个线程封装对象
    reactContext.initializeWithInstance(catalystInstance);

    if (mJSIModulePackage != null) {
      // 这个默认是为null的。这个数据最初是在ReactNativeHost里面传入的
      catalystInstance.addJSIModules(
          mJSIModulePackage.getJSIModules(
              reactContext, catalystInstance.getJavaScriptContextHolder()));
      // 这个地方没太看懂
      if (ReactFeatureFlags.useTurboModules) {
        catalystInstance.setTurboModuleManager(
            catalystInstance.getJSIModule(JSIModuleType.TurboModuleManager));
      }
    }
    if (mBridgeIdleDebugListener != null) {
      catalystInstance.addBridgeIdleDebugListener(mBridgeIdleDebugListener);
    }
    if (Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JS_VM_CALLS)) {
      catalystInstance.setGlobalVariable("__RCTProfileIsProfiling", "true");
    }
    ReactMarker.logMarker(ReactMarkerConstants.PRE_RUN_JS_BUNDLE_START);
    Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "runJSBundle");
    // 加载JSBundle的数据
    catalystInstance.runJSBundle();
    Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);

    return reactContext;
  }

这个是非常重要的方法,我们需要一点点来分析一下。

1、首先他将Application的对象用ReactApplicationContext进行包装,生成ReactApplication对象。这个没什么好说的。简单的包装而已。

2、创建JavaModule的注册表

3、进行CatalystInstanceImpl实例化

4、关联ReacContext与CatalystInstance实例化 解析上面实例化的是三个线程封装对象。这个地方。

我们主要作用是让reactContext来持有catalystInstance对象 两个作用:1、获取这个实力上面传入ReactQueueConfigurationSpec实例,或者三个消息队列线程封装的对象 2、主要是通过催化器实例获取JSModule、NativeModule

其次,ReacContext还有就是一些生命周期的管理

实例化CatalystInstanceImpl

下面就是最重要的催化剂实例的构造方法

private CatalystInstanceImpl(
      final ReactQueueConfigurationSpec reactQueueConfigurationSpec,
      final JavaScriptExecutor jsExecutor,
      final NativeModuleRegistry nativeModuleRegistry,
      final JSBundleLoader jsBundleLoader,
      NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
    Log.d(ReactConstants.TAG, "Initializing React Xplat Bridge.");
    Log.d(TAG, "FMsg:第七步:CatalystInstanceImpl() called with: reactQueueConfigurationSpec = [" + reactQueueConfigurationSpec + "], jsExecutor = [" + jsExecutor + "], nativeModuleRegistry = [" + nativeModuleRegistry + "], jsBundleLoader = [" + jsBundleLoader + "], nativeModuleCallExceptionHandler = [" + nativeModuleCallExceptionHandler + "]");
    Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstanceImpl");

    // 重点关注一下这一方法。这是一个Native方法。这样我们就调用到Native层
    mHybridData = initHybrid();
    // ReactNative的消息队列相关的实例化
    // TODO 这个地方要重点看一下
    // 这个主要是分别在对应的线程中创建消息任务队列的Handler(搬运工)
    // 当然还创建了两个线程(主线程不用创建)
    mReactQueueConfiguration =
        ReactQueueConfigurationImpl.create(
            reactQueueConfigurationSpec, new NativeExceptionHandler());
    mBridgeIdleListeners = new CopyOnWriteArrayList<>();
    // NativeModules注入器
    mNativeModuleRegistry = nativeModuleRegistry;
    mJSModuleRegistry = new JavaScriptModuleRegistry();
    // JSBundlerLoader
    mJSBundleLoader = jsBundleLoader;
    mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
    mNativeModulesQueueThread = mReactQueueConfiguration.getNativeModulesQueueThread();
    mTraceListener = new JSProfilerTraceListener(this);
    Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);

    Log.d(TAG, "FMsg: 第七步:CatalystInstanceImpl() called Initializing React Xplat Bridge before initializeBridge");
    Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "initializeCxxBridge");
    Log.d(TAG, "FMsg:第七步:CatalystInstanceImpl() called with: initializeCxxBridge");

    // TODO 这个地方要重点看一下. 又一个非常重要的方法。
    // 初始化Java和Native之间的Bridge桥。这个是一个Native方法
    initializeBridge(
        //
        new BridgeCallback(this),
        // JSCore的JS引擎
        jsExecutor,
        // JS消息队列线程封装对象
        mReactQueueConfiguration.getJSQueueThread(),
            // Native消息队列线程封装对象
        mNativeModulesQueueThread,
        // 非C++的Modules就是JavaModule.也就是我们在Application里面封装的Modules
        // 这些NativeModules都会被封装成JavaModuleWrapper对象送给Native层
        mNativeModuleRegistry.getJavaModules(this),
        // 获取我们所有的Module中的C++的modules。这个是通过注解来标记那个NativeModule是C++
        // 但是我们翻了一下源码,没看到哪个NativeModule是C++
        mNativeModuleRegistry.getCxxModules());
    Log.d(ReactConstants.TAG, "第七步:实例化Initializing React Xplat Bridge after initializeBridge");
    Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);

    mJavaScriptContextHolder = new JavaScriptContextHolder(getJavaScriptContext());
  }

下面,我们看一下Native层的调用

jni::local_ref<CatalystInstanceImpl::jhybriddata> CatalystInstanceImpl::initHybrid(
    jni::alias_ref<jclass>) {
   cout<<"===========FMsg:CatalystInstanceImpl initHybrid  called==============="<<endl;
  return makeCxxInstance();
}
void CatalystInstanceImpl::initializeBridge(
    jni::alias_ref<ReactCallback::javaobject> callback,
    // This executor is actually a factory holder.
    JavaScriptExecutorHolder* jseh,
    jni::alias_ref<JavaMessageQueueThread::javaobject> jsQueue,
    jni::alias_ref<JavaMessageQueueThread::javaobject> nativeModulesQueue,
    jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
    jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules) {
    LOG(INFO) <<"===========FMsg:CatalystInstanceImpl initializeBridge==============="<<endl;
    // .............省略部分代码

  moduleRegistry_ = std::make_shared<ModuleRegistry>(
    buildNativeModuleList(
       std::weak_ptr<Instance>(instance_),
       javaModules,
       cxxModules,
       moduleMessageQueue_));

  instance_->initializeBridge(
    std::make_unique<JInstanceCallback>(
    callback,
    moduleMessageQueue_),
    jseh->getExecutorFactory(),
    folly::make_unique<JMessageQueueThread>(jsQueue),
    moduleRegistry_);
}

至此,Java层的代码执行完毕。我们彻底就进入Native层的代码逻辑了。上面Jni代码中,调用的instance_->initializeBridge()。 这个逻辑层,我们要到Native层去查找逻辑实现了。

void Instance::initializeBridge(
    std::unique_ptr<InstanceCallback> callback,
    std::shared_ptr<JSExecutorFactory> jsef,
    std::shared_ptr<MessageQueueThread> jsQueue,
    std::shared_ptr<ModuleRegistry> moduleRegistry) {
  LOG(INFO) <<"===========FMsg:Instance initializeBridge==============="<<endl;
  callback_ = std::move(callback);
  moduleRegistry_ = std::move(moduleRegistry);
  jsQueue->runOnQueueSync([this, &jsef, jsQueue]() mutable {
    nativeToJsBridge_ = folly::make_unique<NativeToJsBridge>(
        jsef.get(), moduleRegistry_, jsQueue, callback_);

    std::lock_guard<std::mutex> lock(m_syncMutex);
    m_syncReady = true;
    m_syncCV.notify_all();
  });

  CHECK(nativeToJsBridge_);
}

上线的代码中。催化器对象在启动的流程中的主要作用就完成了。主要就是将催化器初始化的一些Java、Native、JS层的一些通信对象准备好。

我们在回过头去,看catalystInstance.runJSBundle()方法的调用。

  @Override
  public void runJSBundle() {
    Log.d(ReactConstants.TAG, "CatalystInstanceImpl.runJSBundle()");
    Log.d(TAG, "FMsg:第九步:runJSBundle() called");
    Assertions.assertCondition(!mJSBundleHasLoaded, "JS bundle was already loaded!");
    // incrementPendingJSCalls();
    mJSBundleLoader.loadScript(CatalystInstanceImpl.this);

    synchronized (mJSCallsPendingInitLock) {

      // Loading the bundle is queued on the JS thread, but may not have
      // run yet.  It's safe to set this here, though, since any work it
      // gates will be queued on the JS thread behind the load.
      mAcceptCalls = true;

      for (PendingJSCall function : mJSCallsPendingInit) {
        function.call(this);
      }
      mJSCallsPendingInit.clear();
      mJSBundleHasLoaded = true;
    }

    // This is registered after JS starts since it makes a JS call
    Systrace.registerListener(mTraceListener);
  }
  public static JSBundleLoader createFileLoader(
      final String fileName, final String assetUrl, final boolean loadSynchronously) {
    Log.d(TAG, "FMsg:第九步:createFileLoader() called with: fileName = [" + fileName + "], assetUrl = [" + assetUrl + "], loadSynchronously = [" + loadSynchronously + "]");
    return new JSBundleLoader() {
      @Override
      public String loadScript(JSBundleLoaderDelegate delegate) {
        delegate.loadScriptFromFile(fileName, assetUrl, loadSynchronously);
        return fileName;
      }
    };
  }
  @Override
  public void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously) {
    Log.d(TAG, "FMsg:第九步:loadScriptFromFile() called with: fileName = [" + fileName + "], sourceURL = [" + sourceURL + "], loadSynchronously = [" + loadSynchronously + "]");
    mSourceURL = sourceURL;
    jniLoadScriptFromFile(fileName, sourceURL, loadSynchronously);
  }
  

这个jniLoadScriptFromFile也是一个Native的方法,我们可以看到他会调用到CatalystInstanceImpl.cpp的

void CatalystInstanceImpl::jniLoadScriptFromFile(const std::string& fileName,
                                                 const std::string& sourceURL,
                                                 bool loadSynchronously) {
  LOG(INFO) <<"===========FMsg:CatalystInstanceImpl jniLoadScriptFromFile==============="<<endl;
  if (Instance::isIndexedRAMBundle(fileName.c_str())) {
    instance_->loadRAMBundleFromFile(fileName, sourceURL, loadSynchronously);
  } else {
    std::unique_ptr<const JSBigFileString> script;
    RecoverableError::runRethrowingAsRecoverable<std::system_error>(
      [&fileName, &script]() {
        script = JSBigFileString::fromPath(fileName);
      });
    instance_->loadScriptFromString(std::move(script), sourceURL, loadSynchronously);
  }
}

调用到Instancee.cpp的

void Instance::loadScriptFromString(std::unique_ptr<const JSBigString> string,
                                    std::string sourceURL,
                                    bool loadSynchronously) {
  LOG(INFO) <<"===========FMsg:Instance loadScriptFromString==============="<<endl;
  SystraceSection s("Instance::loadScriptFromString", "sourceURL",
                    sourceURL);
  if (loadSynchronously) {
    loadApplicationSync(nullptr, std::move(string), std::move(sourceURL));
  } else {
    loadApplication(nullptr, std::move(string), std::move(sourceURL));
  }
}


void Instance::loadApplication(std::unique_ptr<RAMBundleRegistry> bundleRegistry,
                               std::unique_ptr<const JSBigString> string,
                               std::string sourceURL) {
  LOG(INFO) <<"===========FMsg:Instance loadApplication=========string======"<<endl;
  callback_->incrementPendingJSCalls();
  SystraceSection s("Instance::loadApplication", "sourceURL",
                    sourceURL);
  nativeToJsBridge_->loadApplication(std::move(bundleRegistry), std::move(string),
                                     std::move(sourceURL));
}

下面有调用到了

void NativeToJsBridge::loadApplication(
    std::unique_ptr<RAMBundleRegistry> bundleRegistry,
    std::unique_ptr<const JSBigString> startupScript,
    std::string startupScriptSourceURL) {
   LOG(INFO) <<"===========FMsg:NativeToJsBridge loadApplication==============="<<endl;
  runOnExecutorQueue(
      [this,
       bundleRegistryWrap=folly::makeMoveWrapper(std::move(bundleRegistry)),
       startupScript=folly::makeMoveWrapper(std::move(startupScript)),
       startupScriptSourceURL=std::move(startupScriptSourceURL)]
        (JSExecutor* executor) mutable {
    auto bundleRegistry = bundleRegistryWrap.move();
    if (bundleRegistry) {
      executor->setBundleRegistry(std::move(bundleRegistry));
    }
     //executor从runOnExecutorQueue()返回的map中取得,与OnLoad中的JSCJavaScriptExecutorHolder对应,也与
     //Java中的JSCJavaScriptExecutor对应。它的实例在JSExecutor.cpp中实现。
    try {
      LOG(INFO) <<"===========FMsg:NativeToJsBridge executor  loadApplicationScript======" << startupScriptSourceURL << "。"<<endl;
      executor->loadApplicationScript(std::move(*startupScript),
                                      std::move(startupScriptSourceURL));
    } catch (...) {
      m_applicationScriptHasFailure = true;
      throw;
    }
  });
}

void NativeToJsBridge::runOnExecutorQueue(std::function<void(JSExecutor*)> task) {
  if (*m_destroyed) {
    return;
  }

  std::shared_ptr<bool> isDestroyed = m_destroyed;
  m_executorMessageQueueThread->runOnQueue([this, isDestroyed, task=std::move(task)] {
    if (*isDestroyed) {
      return;
    }

    // The executor is guaranteed to be valid for the duration of the task because:
    // 1. the executor is only destroyed after it is unregistered
    // 2. the executor is unregistered on this queue
    // 3. we just confirmed that the executor hasn't been unregistered above
    task(m_executor.get());
  });
}

下面,我们看到他调用了JSIExecutor的loadApplicationScript。下面我们来看一下这个方法的实现。

void JSIExecutor::loadApplicationScript(
    std::unique_ptr<const JSBigString> script,
    std::string sourceURL) {
  SystraceSection s("JSIExecutor::loadApplicationScript");
  LOG(INFO) <<"===========FMsg:JSIExecutor loadApplicationScript===============sourceURL = " << sourceURL << "。" <<endl;
  // TODO: check for and use precompiled HBC

  runtime_->global().setProperty(
      *runtime_,
      "nativeModuleProxy",
      Object::createFromHostObject(
          *runtime_, std::make_shared<NativeModuleProxy>(*this)));

  runtime_->global().setProperty(
      *runtime_,
      "nativeFlushQueueImmediate",
      Function::createFromHostFunction(
          *runtime_,
          PropNameID::forAscii(*runtime_, "nativeFlushQueueImmediate"),
          1,
          [this](
              jsi::Runtime &,
              const jsi::Value &,
              const jsi::Value *args,
              size_t count) {
            if (count != 1) {
              throw std::invalid_argument(
                  "nativeFlushQueueImmediate arg count must be 1");
            }
            // 应该是JSIExecutor⾥里里⾯面callNativeModules中的delegate_->callNativeModules
            LOG(INFO) <<"===========FMsg:JSIExecutor loadApplicationScript======callNativeModules======="<<endl;
            callNativeModules(args[0], false);
            return Value::undefined();
          }));

  runtime_->global().setProperty(
      *runtime_,
      "nativeCallSyncHook",
      Function::createFromHostFunction(
          *runtime_,
          PropNameID::forAscii(*runtime_, "nativeCallSyncHook"),
          1,
          [this](
              jsi::Runtime &,
              const jsi::Value &,
              const jsi::Value *args,
              size_t count) { return nativeCallSyncHook(args, count); }));

#if DEBUG
  runtime_->global().setProperty(
      *runtime_,
      "globalEvalWithSourceUrl",
      Function::createFromHostFunction(
          *runtime_,
          PropNameID::forAscii(*runtime_, "globalEvalWithSourceUrl"),
          1,
          [this](
              jsi::Runtime &,
              const jsi::Value &,
              const jsi::Value *args,
              size_t count) { return globalEvalWithSourceUrl(args, count); }));
#endif

  if (runtimeInstaller_) {
    runtimeInstaller_(*runtime_);
  }

  bool hasLogger(ReactMarker::logTaggedMarker);
  std::string scriptName = simpleBasename(sourceURL);
  if (hasLogger) {
    ReactMarker::logTaggedMarker(
        ReactMarker::RUN_JS_BUNDLE_START, scriptName.c_str());
  }
  //使用Webkit JSC去解释执行JS
  runtime_->evaluateJavaScript(
      std::make_unique<BigStringBuffer>(std::move(script)), sourceURL);
  flush();
  if (hasLogger) {
    ReactMarker::logMarker(ReactMarker::CREATE_REACT_CONTEXT_STOP);
    ReactMarker::logTaggedMarker(
        ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str());
  }
}

最后代码调用到evaluateJavaScript方法中。这个方法的实现JSCRuntime.cpp中。我们简简单看一下:

jsi::Value JSCRuntime::evaluateJavaScript(
    const std::shared_ptr<const jsi::Buffer> &buffer,
    const std::string& sourceURL) {
  // LOG(INFO) <<"===========FMsg:JSCRuntime evaluateJavaScript===============sourceURL = " << sourceURL << "。" <<endl;
  std::string tmp(
      reinterpret_cast<const char*>(buffer->data()), buffer->size());
  JSStringRef sourceRef = JSStringCreateWithUTF8CString(tmp.c_str());
  JSStringRef sourceURLRef = nullptr;
  if (!sourceURL.empty()) {
    sourceURLRef = JSStringCreateWithUTF8CString(sourceURL.c_str());
  }
  JSValueRef exc = nullptr;
  JSValueRef res =
      JSEvaluateScript(ctx_, sourceRef, nullptr, sourceURLRef, 0, &exc);
  JSStringRelease(sourceRef);
  if (sourceURLRef) {
    JSStringRelease(sourceURLRef);
  }
  checkException(res, exc);
  return createValue(res);
}

从上面的代码中,我们我们开始加载JSBundle的逻辑已经执行完毕。但是这个时候其实ReactNative并没有启动起来。

我们下面来看一下启动流程的最后一步:

我们来回到ReactRootView的startReactApplication这个方法中的最后一步:

  private void attachToReactInstanceManager() {
    Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "attachToReactInstanceManager");
    Log.d(TAG, "FMsg:attachToReactInstanceManager() called");
    try {
      if (mIsAttachedToInstance) {
        return;
      }

      mIsAttachedToInstance = true;
        // ReactInstanceManager绑定到当前的RootView
      Assertions.assertNotNull(mReactInstanceManager).attachRootView(this);
      getViewTreeObserver().addOnGlobalLayoutListener(getCustomGlobalLayoutListener());
    } finally {
      Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
    }
  }

方法很简单,我们来看attachRootView的实现

  public void attachRootView(ReactRoot reactRoot) {
    Log.d(TAG, "FMsg:attachRootView() called with: reactRoot = [" + reactRoot + "]");
    UiThreadUtil.assertOnUiThread();
    // ReactInstanceManager 是支持多 RootView 的.其实这个地方大家可以猜想,其实我们的ReactNative的页面,可以作为一个小的页面View
    // 附着到宿主Activity上。
    mAttachedReactRoots.add(reactRoot);

    // Reset reactRoot content as it's going to be populated by the application content from JS.
    clearReactRoot(reactRoot);

    // If react context is being created in the background, JS application will be started
    // automatically when creation completes, as reactRoot reactRoot is part of the attached
    // reactRoot reactRoot list.
    ReactContext currentContext = getCurrentReactContext();
    if (mCreateReactContextThread == null && currentContext != null) {
      // 最后,取出 ReactContext,让 ReactRootView 与 CatalystInstance 相关联:
      attachRootViewToInstance(reactRoot);
    }
  }
  private void attachRootViewToInstance(final ReactRoot reactRoot) {
    Log.d(ReactConstants.TAG, "ReactInstanceManager.attachRootViewToInstance()");
    Log.d(TAG, "FMsg:第十步:attachRootViewToInstance() called with: reactRoot = [" + reactRoot + "]");
    Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "attachRootViewToInstance");

    // 首先通过 UIManagerHelper 拿到 UIManager:
    // UIManager 是什么呢?它有两个实现类:FabricUIManager、UIManagerModule
    // 我们来看后者,它的注释中说:这是一个原生模块,允许JS创建和更新原生视图。其实这个就是我们后来看RN的渲染流程中非常重要的类
    UIManager uiManager =
        UIManagerHelper.getUIManager(mCurrentReactContext, reactRoot.getUIManagerType());

    @Nullable Bundle initialProperties = reactRoot.getAppProperties();

    final int rootTag =
        uiManager.addRootView(
            reactRoot.getRootViewGroup(),
            initialProperties == null
                ? new WritableNativeMap()
                : Arguments.fromBundle(initialProperties),
            reactRoot.getInitialUITemplate());
    reactRoot.setRootViewTag(rootTag);
    if (reactRoot.getUIManagerType() == FABRIC) {
      // Fabric requires to call updateRootLayoutSpecs before starting JS Application,
      // this ensures the root will hace the correct pointScaleFactor.
      uiManager.updateRootLayoutSpecs(
          rootTag, reactRoot.getWidthMeasureSpec(), reactRoot.getHeightMeasureSpec());
      reactRoot.setShouldLogContentAppeared(true);
    } else {
      Log.d(TAG, "FMsg:第十步:attachRootViewToInstance() called with: reactRoot = [" + reactRoot + "]");
      // 这个方法就是我们真的去调用JS的相关代码,我们可以看看这个代码
      reactRoot.runApplication();
    }
    Systrace.beginAsyncSection(
        TRACE_TAG_REACT_JAVA_BRIDGE, "pre_rootView.onAttachedToReactInstance", rootTag);
    // 这个地方其实,我们有疑问:
    // 为什么使用UiThreadUtil.runOnUiThread。而不是
    //  mCurrentReactContext.runOnUiQueueThread();???
    UiThreadUtil.runOnUiThread(
        new Runnable() {
          @Override
          public void run() {
            Systrace.endAsyncSection(
                TRACE_TAG_REACT_JAVA_BRIDGE, "pre_rootView.onAttachedToReactInstance", rootTag);
            reactRoot.onStage(ReactStage.ON_ATTACH_TO_INSTANCE);
          }
        });
    Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
  }

这个方法的最后一步,我们就可以看到reactRoot.runApplication() 这个方法很明显,就是运行起来JS的相关代码逻辑。

  @Override
  public void runApplication() {
    Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "ReactRootView.runApplication");
    Log.d(TAG, "FMsg:第十一步:ReactRootView runApplication() called");
    try {
      if (mReactInstanceManager == null || !mIsAttachedToInstance) {
        return;
      }

      ReactContext reactContext = mReactInstanceManager.getCurrentReactContext();
      if (reactContext == null) {
        return;
      }

      CatalystInstance catalystInstance = reactContext.getCatalystInstance();
      String jsAppModuleName = getJSModuleName();

      if (mUseSurface) {
        // TODO call surface's runApplication
      } else {
        if (mWasMeasured) {
          updateRootLayoutSpecs(mWidthMeasureSpec, mHeightMeasureSpec);
        }

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

        mShouldLogContentAppeared = true;
        Log.i(TAG, "FMsg: 第十步:==============runApplication: ==========================" + jsAppModuleName);
        Log.i(TAG, "FMsg: 第十步:==============runApplication: ==========================" + appParams);
        catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);
      }
    } finally {
      Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
    }
  }

这个方法也是比较简单的。通过ReactContext的实例,拿到催化器实例。然后通过催化器实例获取JSModule的runApplication

  @Override
  public <T extends JavaScriptModule> T getJSModule(Class<T> jsInterface) {
    // Log.d(TAG, "FMsg:getJSModule() called with: jsInterface = [" + jsInterface + "]");
    // mJSModuleRegistry注入器获取当前的注入器。至于怎么去获取的。我们可以再分析
    return mJSModuleRegistry.getJavaScriptModule(this, jsInterface);
  }

可以看到,最终调用的是 catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams) , AppRegistry.class 是JS层暴露给Java层的接口方法。它的真正实现在 AppRegistry.js 里, AppRegistry.js 是运行所有 RN 应用的 JS 层入口,我们来看看它的实现:在 Libraries/ReactNative 中的 AppRegistry.js

  /**
   * Loads the JavaScript bundle and runs the app.
   *
   * See http://facebook.github.io/react-native/docs/appregistry.html#runapplication
   */
  runApplication(appKey: string, appParameters: any): void {
    const msg =
      'Running "' + appKey + '" with ' + JSON.stringify(appParameters);
    infoLog(msg);
    BugReporting.addSource(
      'AppRegistry.runApplication' + runCount++,
      () => msg,
    );
    invariant(
      runnables[appKey] && runnables[appKey].run,
      `"${appKey}" has not been registered. This can happen if:\n` +
        '* Metro (the local dev server) is run from the wrong folder. ' +
        'Check if Metro is running, stop it and restart it in the current project.\n' +
        "* A module failed to load due to an error and `AppRegistry.registerComponent` wasn't called.",
    );

    SceneTracker.setActiveScene({name: appKey});
    runnables[appKey].run(appParameters);
  },

到这里就会去调用JS进行渲染,在通过 UIManagerModule 将JS组件转换成Android组件,最终显示在 ReactRootView 上。

最后总结一下,就是先在应用终端启动并创建上下文对象,启动 JS Runtime ,进行布局,将JS端的代码通过C++层, UIManagerMoodule 转化成 Android 组件,再进行渲染,最后将渲染的View添加到 ReactRootView 上,最终呈现在用户面前。

2019-03-22 16:27:00 qq_37815596 阅读数 3579

 

  • react map遍历(截取部分重要代码)
{this.state.images.map((img, i) => {
    return (
        <div className="swiperBox" key={"img" + i}>
            <p className="swiperP">
                Updated:{img.left ? img.left.date : img.right.date}
            </p>
        </div>
    );
})}

或者

            {this.props.socks &&
              this.props.socks.map((sock, i) => {
                let randomId = Math.round(Math.random() * 10000);
                let sockDiv = (
                  <Table.Row key={"sock-list" + randomId + i}>
                    <Table.Cell>{sock.mac}</Table.Cell>
                    <Table.Cell>{sock.sn}</Table.Cell>
                    <Table.Cell>{sock.authCode}</Table.Cell>
                    <Table.Cell>{sock.foot}</Table.Cell>
                  </Table.Row>
                );
                return sockDiv;
              })}

 

  • react native map遍历(截取部分重要代码)

 

{this.props.forecastList && this.props.forecastList.daily_forecast && this.props.forecastList.daily_forecast.map((infor, i) => {
                    let weatherDiv =(
                        <View style={ForecastStyle.list} key={"forecast-list" + i}>
                            <View style={ForecastStyle.list1}>
                                <Text style={ForecastStyle.list_date}>{infor[i]&&infor[i].date.split("-")[2]}日</Text>
                                <Text style={ForecastStyle.list_day}>今天</Text>
                            </View>
                            <View style={ForecastStyle.list2}>
                                {(infor[i]&&infor[i].cond.txt_n) === "多云" ? <Cloudy /> : null}
                                <Text style={ForecastStyle.list_weather}>{infor[i]&&infor[i].cond.txt_n}</Text>
                            </View>
                            <View style={ForecastStyle.list3}>
                                <Text style={ForecastStyle.list_tmp}>{infor[i]&&infor[i].tmp.min}~{infor[i]&&infor[i].tmp.max}℃</Text>
                            </View>
                        </View>
                    );
                    return weatherDiv
                })}

 

2019-06-15 09:08:14 ahou2468 阅读数 223

目录

 

1.Map

1.1介绍

1.2描述

2.Map相关操作-增删改查

3.Map排序

3.1以Value排序

3.2以key排序

4.Map和JSON转换


1.Map


1.1介绍

Map 对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。

语法
new Map([iterable])
参数
iterable
Iterable 可以是一个数组或者其他 iterable 对象,其元素为键值对(两个元素的数组,例如: [[ 1, 'one' ],[ 2, 'two' ]])。 每个键值对都会添加到新的 Map。null 会被当做 undefined。

1.2描述

a. Map 的键可以是任意值,包括函数、对象、基本类型;
b.Map 中的键值是有序的,而添加到对象中的键则不是。因此,当对它进行遍历时,Map 对象是按插入的顺序返回键值。
你可以通过 size 属性直接获取一个 Map 的键值对个数。
c.Map 可直接进行迭代;
d.Map 在涉及频繁增删键值对的场景下会有些性能优势。

2.Map相关操作-增删改查

export default class MapLearn {

    //创建Map对象

    constructor(){
        this.map = new Map();

        this.map1 = new Map([[1, 'one'], [2, 'two']]);
    }

    //Map常用操作
    mapCommonOpt(){
        //1.基础操作
        //添加新值
        this.map.set('key', 'value');
        //通过key获取value
        this.map.get('key');
        //删除某个key键值
        this.map.delete('key');
        //删除所有值
        this.map.clear();
        //检测是否包含某个值
        this.map.has('key');
        //获取Map大小-内容长度
        this.map.size;

        //2.获取Map中所有的值
        //循环遍历获取所有值
        for(let [key, value] of this.map){
            console.log(key+"="+value)
        }

        //获取所有的key
        //this.map.keys(); 返回所有的key
        for(let key of this.map.keys()){
            console.log(key);
        }

        //获取所有的key
        //this.map.values(); 返回所有的value
        for(let value of this.map.values()){
            console.log(value);
        }

        //获取Map中所有的值
        //map.entries()返回一个新的 Iterator 对象,它按插入顺序包含了Map对象中每个元素的 [key, value] 数组。
        for(let [key, value] of this.map.entries()){
            console.log(key+"="+value)
        }

        //forEach方法获取所有值
        this.map.forEach(function (value, key) {
            console.log(key+"="+value)
        }, this.map);

        //3.Map与数组转换
        let kvArray = [['key1', 'value1'], ['key2','value2']];
        // 使用常规的Map构造函数可以将一个二维键值对数组转换成一个Map对象
        let kvMap = new Map(kvArray);
        kvMap.get('key1'); //返回value1

        // 使用Array.from函数可以将一个Map对象转换成一个二维键值对数组
        // 输出和kvArray相同的数组
        //[['key1', 'value1'], ['key2','value2']]
        console.log(Array.from(kvMap));


        // 或者在键或者值的迭代器上使用Array.from,进而得到只含有键或者值的数组
        console.log(Array.from(myMap.keys())); // 输出 ["key1", "key2"]

        //4.复制或合并Maps,请记住,数据本身未被克隆。
        let original = new Map([
            [1, 'one']
        ]);
        let clone = new Map(original);
        console.log(clone.get(1)); // one
        console.log(original === clone); // false. Useful for shallow comparison

        //5.Map对象间可以进行合并,但是会保持键的唯一性
        let first = new Map([
            [1, 'one'],
            [2, 'two'],
            [3, 'three'],
        ]);

        let second = new Map([
            [1, 'uno'],
            [2, 'dos']
        ]);

        // 合并两个Map对象时,如果有重复的键值,则后面的会覆盖前面的。
        // 展开运算符本质上是将Map对象转换成数组。
        let merged = new Map([...first, ...second]);

        console.log(merged.get(1)); // uno
        console.log(merged.get(2)); // dos
        console.log(merged.get(3)); // three

    }


}

3.Map排序

 JS 中Map对象会按照元素的写入顺序来保存,有时我们想对Map中的对象进行排序应该怎么做呢?参考别人的回答这里做一个小小的总结;

3.1以Value排序

假如有以下map

var map=new Map();
map.set("b","8");
map.set("c","10");
map.set("a","1");
map.set("d","7");
map.set("e","3");
现在想根据value从小到大排序,首先转换为数组对象

var arrayObj=Array.from(map);
得到的arrayObj中索引0为map中的key,索引1为map中的value,下面可以采用数组的排序方法

arrayObj.sort(function(a,b){return a[1]-b[1]})
 结果为:

(5) [Array(2), Array(2), Array(2), Array(2), Array(2)]
0: (2) ["a", "1"]
1: (2) ["e", "3"]
2: (2) ["d", "7"]
3: (2) ["b", "8"]
4: (2) ["c", "10"]
length: 5
__proto__: Array(0)

3.2以key排序


如果是想按key排序,只需要更改一下sort方法为

arrayObj.sort(function(a,b){return a[0].localeCompare(b[0])})
结果为:

(5) [Array(2), Array(2), Array(2), Array(2), Array(2)]
0: (2) ["a", "1"]
1: (2) ["b", "8"]
2: (2) ["c", "10"]
3: (2) ["d", "7"]
4: (2) ["e", "3"]
length: 5
__proto__: Array(0)
接下来可以这样转换为Map对象:

var result = new Map(arrayObj.map(i => [i[0], i[1]));
结果为:

Map(5) {"a" => "1", "e" => "3", "d" => "7", "b" => "8", "c" => "10"}
size: (...)
__proto__: Map
[[Entries]]: Array(5)
0: {"a" => "1"}
1: {"e" => "3"}
2: {"d" => "7"}
3: {"b" => "8"}
4: {"c" => "10"}
length: 5

4.Map和JSON转换

Json格式(Json字符串) : var json='{"name": "lily","age":"15"}'

Map格式: var map={name: "lily", age:"15"}

 

两者互转(字符串与对象的互转):

let json2map=JSON.parse(json);

let map2json=JSON.stringify(map);

 

参考:

https://blog.csdn.net/xuxiaoyinliu/article/details/89166234

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map