React Native startup process detailed analysis

React Native startup process detailed analysis

Introduction: This article takes the sample project (Android part) created by react-native-cli as an example to analyze the startup process of React Native.

The steps for project creation can refer to the official website. The React Native version analyzed in this article is v0.64.2 .

We know that the above project is an Android application. Open the source code file in android/ directory and you will first find that it creates two java files: MainApplication.java and MainActivity.java , which define the application and the main Activity respectively.

The startup process of an Android application is as follows: a globally unique Application object is created before the first activity is started. So here we first analyze MainApplication

MainApplication

public class MainApplication extends Application implements ReactApplication {
  private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
    @Override
        public boolean getUseDeveloperSupport() {
          return BuildConfig.DEBUG;
        }
        @Override
        protected List<ReactPackage> getPackages() {
          @SuppressWarnings("UnnecessaryLocalVariable")
          List<ReactPackage> packages = new PackageList(this).getPackages();
          // Other operations on packages return packages;
        }
        @Override
        protected String getJSMainModuleName() {
          return "index";
        }
  }
  @Override
  public ReactNativeHost getReactNativeHost() {
    return mReactNativeHost;
  }
  @Override
  public void onCreate() {
    super.onCreate();
    SoLoader.init(this, /* native exopackage */ false);
    initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
  }

MainApplication inherits from Application class and implements ReactApplication interface. Things to do include:

1. Create an instance of the member variable ReactNativeHost , and inject some configurations by overriding the ReactNativeHost class method during the creation process, including:

  1. getUseDeveloperSupport: Configure whether to enable debugging
  2. getPackages: configure the modules to load
  3. getJSMainModuleName: configure the entry file name of the js module

2. In onCreate:

  1. Call the Soloader library. Soloader is a so file loading library launched by Facebook. It can handle the dependency of so files. In react-native, all framework-related so files are loaded through SoLoader.
  2. Initialize Flipper through ReactInstanceManager . Flipper is a tool launched by Facebook for debugging iOS, Android, and React Native applications.

Here is a brief introduction to ReactNativeHost and ReactInstanceManager

ReactNativeHost

ReactNativeHost is an abstract class, and developers can override its methods. Its main function is to specify some assignment operations in the application and then obtain an instance of ReactInstanceManager . Therefore, ReactNativeHost can be used as a transit station for assigning user-defined parameters to ReactInstanceManager instances. The core method is: getReactInstanceManager , see below for detailed analysis.

ReactInstanceManager

This class is the core class, which is mainly responsible for managing JS loading, maintaining the life cycle, managing the interaction between JS and C++, and so on. ReactInstanceManager can be understood as a transfer bridge between JS and C++.

MainActivity

Next, look at MainActivity.java :

public class MainActivity extends ReactActivity {
  @Override
  protected String getMainComponentName() {
    return "myProject";
  }
}

Only the getMainComponentName method is overridden in MainActivity class. This class inherits from ReactActivity . Let's look at its ReactActivity .

public abstract class ReactActivity extends AppCompatActivity
    implements DefaultHardwareBackBtnHandler, PermissionAwareActivity {
  private final ReactActivityDelegate mDelegate;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mDelegate.onCreate(savedInstanceState);
  }

ReactActivity fully delegates to ReactActivityDelegate to handle onCreate life cycle. Let's look at ReactActivityDelegate 's onCreate .

protected void onCreate(Bundle savedInstanceState) {
  String mainComponentName = getMainComponentName();
  mReactDelegate =
      new ReactDelegate(
          getPlainActivity(), getReactNativeHost(), mainComponentName, getLaunchOptions()) {
        @Override
        protected ReactRootView createRootView() {
          return ReactActivityDelegate.this.createRootView();
        }
      };
    if (mMainComponentName != null) {
      loadApp(mainComponentName);
    }
  }

Here, the ReactDelegate instance is first created. Next, let's look at loadApp method:

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

From here we go to the loadApp method of the ReactDelegate instance:

public void loadApp(String appKey) {
  if (mReactRootView != null) {
    throw new IllegalStateException("Cannot loadApp while app is already running.");
  }
  mReactRootView = createRootView();
  mReactRootView.startReactApplication(
      getReactNativeHost().getReactInstanceManager(), appKey, mLaunchOptions);
}

Three things are done here: create rootView ( createRootView ), create ReactInstanceManager ( getReactInstanceManager ), and create ReactApplication ( startReactApplication ).

createRootView

First, let’s take a look at what rootView is.

public class ReactRootView extends FrameLayout implements RootView, ReactRoot { /* ... */}

ReactRootView inherits from FrameLayout and implements RootView and ReactRoot interfaces. FrameLayout is one of the simpler layouts in Android. The entire interface is treated as a blank spare area, and all elements are stacked with the upper left corner aligned. ReactRootView inherits from FrameLayout , indicating that it also exists as a simple layout, and UI 的繪制渲染occur on it.

getReactInstanceManager

ReactInstanceManager is a core class that manages JS loading, C++ and JS interaction, initialization parameters, etc. Finally, the call comes to createReactInstanceManager method in ReactNativeHost class:

protected ReactInstanceManager createReactInstanceManager() {
  ReactInstanceManagerBuilder builder = /* ... */

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

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

Here’s what’s happening:

  • Create ReactInstanceManagerBuilder instance. The builder pattern is used here to construct the ReactInstanceManager instance, so the parameters are passed in to set the constructor first;
  • Add all packages registered in ReactNativeHost to the ReactInstanceManagerBuilder instance;
  • If getJSBundleFile is not empty, load the corresponding file, otherwise load the default jsBundleFile ;
  • Call builder.build method. Actually construct ReactInstanceManager instance through the builder

startReactApplication

  public void startReactApplication(/* */) {
    // ...
    try {
      // ...
      mReactInstanceManager.createReactContextInBackground();
    finally
      // ...
    }
  }

Finally, the execution is carried out into the createReactContextInBackground method of ReactInstanceManager . Finally, the call chain is: recreateReactContextInBackgroundInner() -> recreateReactContextInBackgroundFromBundleLoader() -> recreateReactContextInBackground() -> runCreateReactContextOnNewThread()

runCreateReactContextOnNewThread mainly does two things:

  1. Create a new thread and create ReactContext context through createReactContext in the new thread;
  2. The context environment is set up through setupReactContext , and finally AppRegistry.js is called to start the App.

We will put the detailed analysis in another article: React Native startReactApplication process analysis.

Summarize

To summarize this article, we take the sample project (Android part) created by react-native-cli as an example, follow the execution flow of the two classes MainApplication and MainActivity , grasp the main logic, and finally sort out the process of React Native from starting to executing user js files. You can see:

The main function of MainApplication is to pass in the user's configuration and initialize the so library and application debug tools;

The main functions of MainActivity are:

  1. Create a rootView layout container for the application;
  2. Create ReactInstanceManager core class to manage JS loading, C++ and JS interaction, initialization parameters, etc.
  3. ReactContext context is created through startReactApplication , and finally AppRegistry.js is called to start the App.

This is the end of this article about the brief analysis of the React Native startup process. For more relevant React Native startup content, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • React native ScrollView pull down refresh effect
  • A brief analysis of React Native startReactApplication method
  • In-depth understanding of React Native custom routing management
  • How to use Lottie animation in React Native project

<<:  Analysis of the principle and creation method of Mysql temporary table

>>:  Solution to the problem of IP loss caused by copying centos8 virtual machine under VMWARE

Recommend

CentOS 7.5 deploys Varnish cache server function

1. Introduction to Varnish Varnish is a high-perf...

The difference between docker run and start

The difference between run and start in docker Do...

Detailed tutorial on installing mysql8.0.22 on Alibaba Cloud centos7

1. Download the MySQL installation package First ...

Docker deploys nginx and mounts folders and file operations

During this period of time, I was studying docker...

MySQL cross-database transaction XA operation example

This article uses an example to describe the MySQ...

Sample code for implementing dark mode with CSS variables

Recently, WeChat was forced by Apple to develop a...

Detailed explanation of the use of umask under Linux

I recently started learning Linux. After reading ...

How to automatically execute SQL statements when MySQL in Docker starts

When creating a MySQL container with Docker, some...

MySQL DeadLock troubleshooting full process record

【author】 Liu Bo: Senior Database Manager at Ctrip...

MySQL recursion problem

MySQL itself does not support recursive syntax, b...

Installation and use of Ubuntu 18.04 Server version (picture and text)

1 System Installation Steps OS Version:1804 Image...

mysql 5.7.19 latest binary installation

First download the zip archive version from the o...

Detailed explanation of how to configure Nginx web server sample code

Overview Today we will mainly share how to config...

Docker uses the nsenter tool to enter the container

When using Docker containers, it is more convenie...