Eine kurze Analyse der startReactApplication-Methode von React Native

Eine kurze Analyse der startReactApplication-Methode von React Native

In diesem Artikel haben wir den Startvorgang von RN geklärt. Da die endgültige startReactApplication relativ komplex ist und den Prozess der endgültigen Ausführung des Front-End js beinhaltet, haben wir sie separat extrahiert und in einem unabhängigen Artikel analysiert.

Sehen wir uns zunächst an, wo startReactApplication aufgerufen wird:

mReactRootView.startReactApplication(
    getReactNativeHost().getReactInstanceManager(), appKey, mLaunchOptions);

Sie können sehen, dass startReactApplication auf rootView aufgerufen wird und die Eingabeparameter instanceManager、appKey、mLaunchOptions sind.

Folgen Sie startReactApplication , um die Aufrufkette herauszufinden:

mReactInstanceManager.createReactContextInBackground() -> recreateReactContextInBackgroundInner() -> recreateReactContextInBackgroundFromBundleLoader() -> recreateReactContextInBackground() -> runCreateReactContextOnNewThread()

recreateReactContextInBackground ist eine Methode in ReactInstanceManager , die zwei Dinge tut:

1. Erstellen Sie eine ReactContextInitParams -Instanz initParams , wie unten gezeigt. Der Eingabeparameter jsExecutorFactory wird beim Erstellen ReactInstanceManager übergeben.

endgültige ReactContextInitParams initParams =
    neue ReactContextInitParams(jsExecutorFactory, jsBundleLoader);

2. Rufen Sie runCreateReactContextOnNewThread auf

runCreateReactContextOnNewThread ist eine Methode in ReactInstanceManager , die hauptsächlich zwei Dinge tut:

  1. Erstellen Sie einen neuen Thread und erstellen Sie über createReactContext ReactContext -Kontext im neuen Thread.
  2. Die Kontextumgebung wird über setupReactContext eingerichtet und schließlich wird AppRegistry.js aufgerufen, um die App zu starten.

ReactContext erstellen

Schauen Sie sich zunächst an, wo es heißt:

endgültiger ReactApplicationContext reactApplicationContext =
    erstelleReactContext(
        initParams.getJsExecutorFactory().create(),
        initParams.getJsBundleLoader());

Seine beiden Eingabeparameter sind JavaScriptExecutor von JsExecutorFactory erstellte JavaScriptExecutor-Instanz und JsBundleLoader -Instanz.

JavaScriptExecutor

Der erste Eingabeparameter startReactApplication ist getReactNativeHost().getReactInstanceManager() um ReactInstanceManager Instanz zu erhalten. Es gibt nur eine ReactInstanceManager Instanz in der RN-Anwendung, die zuvor bei der Erstellung MainActivity erstellt wurde.

Wenn wir auf den Startvorgang von React Native zurückblicken, wird während des Erstellungsprozesses tatsächlich die folgende Methode aufgerufen:

ReactInstanceManager reactInstanceManager = builder.build()

builder ist ReactInstanceManagerBuilder . Wir kommen zur build -Methode dieser Klasse und stellen fest, dass sie schließlich return new ReactInstanceManager(...) ausführt. Der vierte Parameter im Konstruktionsparameter ist: getDefaultJSExecutorFactory . Wir kommen zu seiner Definition:

 private JavaScriptExecutorFactory getDefaultJSExecutorFactory(
      String Anwendungsname, String Gerätename, Kontext Anwendungskontext) {
    versuchen {
      // Wenn JSC enthalten ist, verwenden Sie es wie gewohnt
      initializeSoLoaderIfNecessary(Anwendungskontext);
      SoLoader.loadLibrary("jscexecutor");
      gibt neue JSCExecutorFactory (Anwendungsname, Gerätename) zurück;
    } Fang (UnsatisfiedLinkError jscE) { /* ... */ }
}

Das heißt, wenn wir ReactInstanceManagerBuilder erstellen, erstellen wir JSCExecutorFactory und rufen dann ihre create Methode auf, um JSCExecutor zu erstellen. JSCExecutorFactory implementiert die Schnittstelle JavaScriptExecutorFactory . Die Methode create lautet wie folgt und gibt JSCExecutor Instanz zurück:

 @Überschreiben
  öffentliches JavaScriptExecutor create() wirft Exception {
    WritableNativeMap jscConfig = neue WritableNativeMap();
    jscConfig.putString("OwnerIdentity", "ReactNative");
    jscConfig.putString("AppIdentity", mAppName);
    jscConfig.putString("Geräteidentität", mGerätename);
    gibt neuen JSCExecutor(jscConfig) zurück;
  }

Ein Blick auf die Definition von JSCExecutor zeigt, dass es von JavaScriptExecutor erbt:

@DoNotStrip
/* Paket */ Klasse JSCExecutor erweitert JavaScriptExecutor {
  statisch {
    SoLoader.loadLibrary("jscexecutor");
  }
  /* Paket */ JSCExecutor(ReadableNativeMap jscConfig) {
    super(initHybrid(jscConfig));
  }
  @Überschreiben
  öffentliche Zeichenfolge getName() {
    gibt "JSCExecutor" zurück;
  }
  private statische native HybridData initHybrid(ReadableNativeMap jscConfig);
}

Es ist also klar, dass der erste Parameter von createReactContext eine JSCExecutor Instanz ist, bei der es sich um ein von SoLoader geladenes C++-Modul handelt.

JsBundleLoader

Ebenso lautet im return new ReactInstanceManager(...) der fünfte Parameter in den Konstruktionsparametern: JSBundleLoader.createAssetLoader(mApplication, mJSBundleAssetUrl, false)

Bei der Definition habe ich festgestellt, dass es eine JSBundleLoader Instanz zurückgibt und deren loadScript -Methode überschreibt.

öffentlicher statischer JSBundleLoader createAssetLoader(
    finaler Kontext Kontext, finaler String AssetUrl, finaler Boolean LoadSynchronously) {
  returniere neuen JSBundleLoader() {
    @Überschreiben
    öffentliche Zeichenfolge loadScript(JSBundleLoaderDelegate-Delegierter) {
      delegate.loadScriptFromAssets(context.getAssets(), assetUrl, synchron laden);
      AssetUrl zurückgeben;
    }
  };
}

Nachdem wir die JSCExecutor Instanz und JSBundleLoader Instanz erstellt haben, geben wir offiziell die Methode createReactContext ein.

ReactContext erstellen

privater ReactApplicationContext erstelleReactContext(
  endgültiger ReactApplicationContext reactContext = neuer ReactApplicationContext(mApplicationContext);

  CatalystInstanceImpl.Builder catalystInstanceBuilder = /* ... */

  versuchen {
    catalystInstance = catalystInstanceBuilder.build();
  } Endlich { /* ... */ }

  reactContext.initializeWithInstance(Katalysatorinstanz);

  TurboModuleManager turboModuleManager =
    neuer TurboModuleManager( /* ... */ )

  catalystInstance.setTurboModuleManager(turboModuleManager);

  if (mJSIModulePackage != null) {
    catalystInstance.addJSIModules( /* ... */ );
  }

  catalystInstance.runJSBundle();
  reactContext zurückgeben;

Darin wird zuerst reactContext erstellt und catalystInstance wird über catalystInstanceBuilder erstellt. Anschließend werden reactContext und catalystInstance über die Methode initializeWithInstance verknüpft und eine Reihe von Aufgaben ausgeführt, um catalystInstance zu initialisieren. Geben Sie abschließend die Methode catalystInstance.runJSBundle() ein.

initialisierenMitInstanz

Durch den Aufruf getUIQueueThread , getNativeModulesQueueThread und getJSQueueThread werden drei Thread-Warteschlangen erstellt, nämlich UI-Thread, NativeModules-Thread und JS-Thread.

Führen Sie JSBundle aus.

öffentliche Leere runJSBundle() {
  mJSBundleLoader.loadScript(CatalystInstanceImpl.this);
  synchronisiert (mJSCallsPendingInitLock) {
    mAcceptCalls = wahr;
    für (PendingJSCall-Funktion: mJSCallsPendingInit) {
      Funktion.Aufruf(dies);
    }
    mJSCallsPendingInit.clear();
    mJSBundleHasLoaded = wahr;
  }
  Systrace.registerListener(mTraceListener);
}

Führen Sie die loadScript -Methode über mJSBundleLoader aus:

öffentliche Zeichenfolge loadScript(JSBundleLoaderDelegate-Delegierter) {
  delegate.loadScriptFromAssets(context.getAssets(), assetUrl, synchron laden);
  AssetUrl zurückgeben;
}

loadScriptFromAssets befindet sich in CatalystInstanceImpl :

öffentliche void loadScriptFromAssets(
    AssetManager assetManager, String assetURL, boolean synchron laden) {
  mSourceURL = Asset-URL;
  jniLoadScriptFromAssets(assetManager, assetURL, synchron laden);
}

assetURL wird hier übergeben, wenn createAssetLoader mJSBundleLoader erstellt, und ihre Zuweisungszeit erfolgt in der reactInstanceManagerBuilder -Instanz, und zwar durch die createReactInstanceManager -Methode reactNativeHost -Instanz. Wenn der Entwickler assetURL durch Überschreiben der Methode getJSBundleFile in MainApplication.java angepasst hat, wird diese URL verwendet. Andernfalls wird die Systemvorgabe verwendet, z. B. file://sdcard/myapp_cache/index.android.bundle .

Die Methode jniLoadScriptFromAssets ist auf der C++-Seite definiert und wird zum Lesen von JS-Dateien verwendet. Warum können C++-Methoden direkt aus Java-Code aufgerufen werden? Diese Frage wird später bei der Analyse der Kommunikation zwischen Java und C++ sowie zwischen Java und JS erläutert.

reactContext wird über createReactContext erstellt, die catalystInstance -Instanz wird erstellt und die beiden werden verknüpft, und dann wird die js-Datei über catalystInstance gelesen. Als Nächstes betreten wir setupReactContext .

ReactContext einrichten

private void setupReactContext(finaler ReactApplicationContext reactContext) {
    synchronisiert (mAttachedReactRoots) {
      catalystInstance.initialize();
      für (ReactRoot reactRoot : mAttachedReactRoots) {
        wenn (reactRoot.getState().compareAndSet(ReactRoot.STATE_STOPPED, ReactRoot.STATE_STARTED)) {
          Fügt RootViewToInstance hinzu (reactRoot);
        }
      }
    }
    UiThreadUtil.runOnUiThread(
      öffentliche Leere ausführen() {
        listener.onReactContextInitialisiert(reactContext);
      }
    )
    reactContext.runOnJSQueueThread(
      öffentliche Leere ausführen() {
        Prozess.setThreadPriority(Prozess.THREAD_PRIORITY_DEFAULT);
      }
    )
    reactContext.runOnNativeModulesQueueThread(
      öffentliche Leere ausführen() {
        Prozess.setThreadPriority(Prozess.THREAD_PRIORITY_DEFAULT);
      }
    )
}

Folgendes passiert hier:

  • catalystInstance.initialize(): Initialisierung aller nativen Module
  • attachRootViewToInstance(reactRoot): Zeichnet alle RootViews und fügt sie den entsprechenden Instanzen hinzu und legt die entsprechenden Listening-Events fest
  • Erstellen Sie Threads für UI-Module, JS-Module und native Module und legen Sie die Priorität der Threads fest, in denen sich das JS-Modul und das native Modul befinden.

Zusammenfassung dieses Artikels

Ausgehend vom Quellcode der Methoden createReactContext und setupReactContext wird der Ausführungsprozess der RN-Methode startReactApplication analysiert, einschließlich:

Die Hauptfunktion von createReactContext besteht darin, reactContext zu erstellen, catalystInstance -Instanz zu erstellen, die beiden zu verknüpfen und dann die js-Datei über catalystInstance zu lesen.

Die Hauptfunktion von setupReactContext besteht darin, alle nativen Module zu initialisieren, alle Rootviews zu zeichnen, UI-Modul-, JS-Modul- und native Modul-Threads zu erstellen und Prioritäten festzulegen.

Dies ist das Ende dieses Artikels über die React Native startReactApplication-Methode. Weitere verwandte Inhalte zu React Native startReactApplication finden Sie in den vorherigen Artikeln von 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird!

Das könnte Sie auch interessieren:
  • Reagieren Sie auf den nativen ScrollView-Pulldown-Aktualisierungseffekt
  • Detaillierte Analyse des React Native-Startvorgangs
  • Tiefgreifendes Verständnis des benutzerdefinierten Routing-Managements von React Native
  • So verwenden Sie Lottie-Animationen in React Native-Projekten

<<:  Analyse der Nginx-Konfiguration und häufig gestellter Fragen des Alibaba Cloud CentOS7-Servers

>>:  Zusammenfassung der grundlegenden Kenntnisse zur MySql-Datenbank

Artikel empfehlen

So simulieren Sie eine Aufzählung mit JS

Vorwort Im aktuellen JavaScript gibt es kein Konz...

Zusammenfassung der MySQL-Injection-Bypass-Filtertechniken

Schauen wir uns zunächst den GIF-Vorgang an: Fall...

Beispiel zum Referenzieren von Umgebungsvariablen in Docker Compose

In einem Projekt müssen Sie häufig Umgebungsvaria...

So zeigen Sie den Startparameterbefehl „Docker Run“ an (empfohlen)

Verwenden Sie runlike, um die Docker Run-Startpar...

RGB-Farbtabellensammlung

RGB-Farbtabelle Farbe Englischer Name RGB 16 Farb...

So stellen Sie das Crownblog-Projekt mit Docker in der Alibaba Cloud bereit

Front-End-Projektpaketierung Suchen Sie .env.prod...

Alibaba Cloud ESC Server Docker-Bereitstellung von Single Node Mysql

1. Laden Sie die beschleunigte Version von msyql ...

Ubuntu öffnet Port 22

Szenario Sie müssen das Xshell-Tool verwenden, um...

So bereinigen Sie Ihre Docker-Daten vollständig

Inhaltsverzeichnis Regelmäßig beschneiden Spiegel...