做了2年React Native,之前也看過一些Android 方面的文章,自己也都只是看了個大概,也就是一知半解,現在想着自己看一遍,好提升一下自己。 我文筆不怎麼好,這個主要是用於自己學習記錄的。
我們都知道一個RN項目創建出來的時候Android 原生會有2個文件 一個MainActivity,一個MainApplication。現在我們來看看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(); // Packages that cannot be autolinked yet can be added manually here, for example: // packages.add(new MyReactNativePackage()); 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); } }
這個Application 會 實現一個接口 ReactApplication
public interface ReactApplication { /** * Get the default {@link ReactNativeHost} for this app. */ ReactNativeHost getReactNativeHost(); }
這個接口值生命了一個方法,很簡單。
然後我們在去看MainApplication 裏面實現了getReactNativeHost 這個方法 返回了在MainApplication中生命的 ReactNativeHost(mReactNativeHost)
ReactNativeHost
public abstract class ReactNativeHost { private final Application mApplication; // Application上下文對象 private @Nullable ReactInstanceManager mReactInstanceManager; // ReactInstanceManager實例 protected ReactNativeHost(Application application) { mApplication = application; // 實例化的時候將 application 傳入並持有 } /** *獲得當前的ReactInstanceManager, 如果沒有則進行創建 */ 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; } /** * 判斷當前的ReactNativeHost是否持用ReactInstanceManager實例 */ public boolean hasInstance() { return mReactInstanceManager != null; } /** * 銷燬當前持有的ReactInstanceManager實例 */ public void clear() { if (mReactInstanceManager != null) { mReactInstanceManager.destroy(); mReactInstanceManager = null; } } protected ReactInstanceManager createReactInstanceManager() { ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_START); // 通過Builder設計模式,來構建ReactInstanceManager實例 ReactInstanceManagerBuilder builder = ReactInstanceManager.builder() .setApplication(mApplication) .setJSMainModulePath(getJSMainModuleName()) .setUseDeveloperSupport(getUseDeveloperSupport()) .setRedBoxHandler(getRedBoxHandler()) .setJavaScriptExecutorFactory(getJavaScriptExecutorFactory()) .setUIImplementationProvider(getUIImplementationProvider()) .setJSIModulesPackage(getJSIModulePackage()) .setInitialLifecycleState(LifecycleState.BEFORE_CREATE); // 將 getPackages 中註冊的ReactPackage 都註冊到 ReactInstanceManager 中 for (ReactPackage reactPackage : getPackages()) { builder.addPackage(reactPackage); } // 這個方法是用於 如果你的jsbundle 不是放在assets中的時候可以指定bundle加載的路徑 String jsBundleFile = getJSBundleFile(); if (jsBundleFile != null) { builder.setJSBundleFile(jsBundleFile); } else { // Assertions.assertNotNull(getBundleAssetName()) 這個方法僅僅只是判斷 getBundleAssetName() 的 返回結果是否爲null builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName())); } ReactInstanceManager reactInstanceManager = builder.build(); ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_END); return reactInstanceManager; // 返回 ReactInstanceManager 實例 } /** * Get the {@link RedBoxHandler} to send RedBox-related callbacks to. */ protected @Nullable RedBoxHandler getRedBoxHandler() { return null; } /** * Get the {@link JavaScriptExecutorFactory}. Override this to use a custom * Executor. */ protected @Nullable JavaScriptExecutorFactory getJavaScriptExecutorFactory() { return null; } protected final Application getApplication() { return mApplication; } /** * Get the {@link UIImplementationProvider} to use. Override this method if you want to use a * custom UI implementation. * * Note: this is very advanced functionality, in 99% of cases you don't need to override this. */ protected UIImplementationProvider getUIImplementationProvider() { return new UIImplementationProvider(); } protected @Nullable JSIModulePackage getJSIModulePackage() { return null; } /** * Returns the name of the main module. Determines the URL used to fetch the JS bundle * from the packager server. It is only used when dev support is enabled. * This is the first file to be executed once the {@link ReactInstanceManager} is created. * e.g. "index.android" */ protected String getJSMainModuleName() { return "index.android"; } /** * Returns a custom path of the bundle file. This is used in cases the bundle should be loaded * from a custom path. By default it is loaded from Android assets, from a path specified * by {@link getBundleAssetName}. * e.g. "file://sdcard/myapp_cache/index.android.bundle" */ protected @Nullable String getJSBundleFile() { return null; } /** * Returns the name of the bundle in assets. If this is null, and no file path is specified for * the bundle, the app will only work with {@code getUseDeveloperSupport} enabled and will * always try to load the JS bundle from the packager server. * e.g. "index.android.bundle" */ protected @Nullable String getBundleAssetName() { return "index.android.bundle"; } /** * Returns whether dev mode should be enabled. This enables e.g. the dev menu. */ public abstract boolean getUseDeveloperSupport(); /** * Returns a list of {@link ReactPackage} used by the app. * You'll most likely want to return at least the {@code MainReactPackage}. * If your app uses additional views or modules besides the default ones, * you'll want to include more packages here. */ protected abstract List<ReactPackage> getPackages(); }