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

Verschiedene Arten von MySQL-Indizes

Was ist ein Index? Ein Index ist eine Datenstrukt...

Beispiel für die Erschöpfung der MySQL-Auto-Increment-ID

Anzeigedefinitions-ID Wenn die in der Tabelle def...

JavaScript Canvas implementiert Grafiken und Text mit Schatten

Verwenden Sie Canvas, um Grafiken und Text mit Sc...

HTML-Tutorial: DOCTYPE-Abkürzung

Beim Schreiben von HTML-Code sollte die erste Zei...

Nginx' praktische Methode zur Lösung domänenübergreifender Probleme

Trennen Sie Front- und Backend und lösen Sie domä...

Zeitleistenimplementierungsmethode basierend auf ccs3

In Webprojekten nutzen wir häufig die Zeitleisten...

Verwenden Sie HTML und CSS, um Ihren eigenen warmen Mann „Dabai“ zu erstellen.

Das Endergebnis sieht so aus, ist es nicht süß … ...

Die Auswirkungen des Limits auf die Abfrageleistung in MySQL

I. Einleitung Lassen Sie mich zunächst die MySQL-...

So ändern Sie die inländische Imagequelle für Docker

Konfigurieren Sie den Beschleuniger für den Docke...

JavaScript+HTML zur Implementierung eines Studenteninformationsmanagementsystems

Inhaltsverzeichnis 1. Einleitung 2. Rendern 3. Co...

Über Generika der C++ TpeScript-Reihe

Inhaltsverzeichnis 1. Vorlage 2. Generika 3. Gene...

Docker verwendet Dockerfile, um die Node.js-Anwendung zu starten

Schreiben einer Docker-Datei Am Beispiel des von ...