Jetpck之App Startup

1,255 阅读2分钟

1.为什么需要App Startup

当一个主项目引用了一些库时,如果这些库在启动的时候需要初始化一些参数。有两种方法,一种是在文档中告知用户自己在主项目的Application中进行初始化;另一种是库的开发者自己通过新建Content Provider来进行初始化操作(因为在进入主Activity之前,会先读取所有的Content Provider组件)。

2.什么是App Startup

其本质就是一个Content Provider

3.为什么可以使用App Startup(Content Provider)来进行初始化?

先说结论:因为组件生命周期回调执行顺序为:Application.attachBaseContext()->ContentProvider.onCreate()->Application.onCreate()

3.1 ActivityThread.main()

public static void main(String[] args) {
      ActivityThread thread = new ActivityThread();
      thread.attach(false, startSeq);
 }

//这个对象就是用来进程间传递信息的
final ApplicationThread mAppThread = new ApplicationThread();

 private void attach(boolean system, long startSeq) {
     final IActivityManager mgr = ActivityManager.getService();
     //这里会生成一个ActivityManagerService对象
     mgr.attachApplication(mAppThread, startSeq);
}

3.2 ActivityThread.attachApplication()

 public final void attachApplication(IApplicationThread thread, long startSeq) {
      attachApplicationLocked(thread, callingPid, callingUid, startSeq);
 }

 private final boolean attachApplicationLocked(IApplicationThread thread,int pid, int callingUid, long startSeq) {
     List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
      //这里的thread就是ApplicationThread
     thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
                        null, null, null, testMode,
                        mBinderTransactionTrackingEnabled, enableTrackAllocation,
                        isRestrictedBackupMode || !normalMode, app.isPersistent(),
                        new Configuration(app.getWindowProcessController().getConfiguration()),
                        app.compat, getCommonServicesLocked(app.isolated),
                        mCoreSettingsObserver.getCoreSettingsLocked(),
                        buildSerial, autofillOptions, contentCaptureOptions);
}

3.3 ApplicationThread.bindApplication()

  public final void bindApplication(String processName, ApplicationInfo appInfo,
                List<ProviderInfo> providers, ComponentName instrumentationName,
                ProfilerInfo profilerInfo, Bundle instrumentationArgs,
                IInstrumentationWatcher instrumentationWatcher,
                IUiAutomationConnection instrumentationUiConnection, int debugMode,
                boolean enableBinderTracking, boolean trackAllocation,
                boolean isRestrictedBackupMode, boolean persistent, Configuration config,
                CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
                String buildSerial, AutofillOptions autofillOptions,
                ContentCaptureOptions contentCaptureOptions) {
    //发送hander消息
    sendMessage(H.BIND_APPLICATION, data);
}

class H extends Handler {
  public void handleMessage(Message msg) {
            switch (msg.what) {
                case BIND_APPLICATION:
                    AppBindData data = (AppBindData)msg.obj;
                    handleBindApplication(data);
                    break;
}

private void handleBindApplication(AppBindData data) {
    Application app;
    //这里最终会调用application实例,同时调用attach方法,从而调用 attachBaseContext()方法
   app = data.info.makeApplication(data.restrictedBackupMode, null);
  //这里会实例化所有的contentProvider,并调用onCreate()方法,同时通知给AMS告诉其他进程
   installContentProviders(app, data.providers);
    //这里会调用application的onCreate()方法
   mInstrumentation.callApplicationOnCreate(app);
}

4.如何使用

官方文档

5.为什么可以这么使用

 <provider
            android:name="androidx.startup.InitializationProvider"
            android:authorities="${applicationId}.androidx-startup"
            android:exported="false"
            tools:node="merge">

            <!-- 自动初始化 -->
            <meta-data
                android:name="cn.woochen.common_config.LibraryConfig"
                android:value="androidx.startup" />

        <!--  手动初始化(也是延迟初始化)-->
            <meta-data
                android:name="cn.woochen.common_config.LibraryConfig"
                android:value="androidx.startup"
                tools:node="remove" />

</provider>

//手动初始化的过程
AppInitializer.getInstance(context).initializeComponent(LibraryConfig::class.java)

下面分析自动初始化

5.1 InitializationProvider.onCreate()

    public boolean onCreate() {
        AppInitializer.getInstance(context).discoverAndInitialize();
    }

    void discoverAndInitialize() {
        try {
             //satrtup=androidx.startup
            String startup = mContext.getString(R.string.androidx_startup);
            if (metadata != null) {
                Set<Class<?>> initializing = new HashSet<>();
                Set<String> keys = metadata.keySet();
                for (String key : keys) {
                    String value = metadata.getString(key, null);
                    if (startup.equals(value)) {
                        Class<?> clazz = Class.forName(key);
                        if (Initializer.class.isAssignableFrom(clazz)) {
                            Class<? extends Initializer<?>> component =
                                    (Class<? extends Initializer<?>>) clazz;
                            mDiscovered.add(component);
                            if (StartupLogger.DEBUG) {
                                StartupLogger.i(String.format("Discovered %s", key));
                            }
                            //遍历meta,找到所有value为androidx.startup,把相应key对应的Initializer组件加入集合
                            doInitialize(component, initializing);
                        }
                    }
                }
            }
        } 
    }

5.2 AppInitializer.doInitialize()

注:手动初始化执行的也是这里

    <T> T doInitialize(
            @NonNull Class<? extends Initializer<?>> component,
            @NonNull Set<Class<?>> initializing) {
        synchronized (sLock) {
            try {
                Object result;
                if (!mInitialized.containsKey(component)) {
                    initializing.add(component);
                    try {
                        Object instance = component.getDeclaredConstructor().newInstance();
                        Initializer<?> initializer = (Initializer<?>) instance;
                        List<Class<? extends Initializer<?>>> dependencies =
                                initializer.dependencies();
                        if (!dependencies.isEmpty()) {
                            for (Class<? extends Initializer<?>> clazz : dependencies) {
                                if (!mInitialized.containsKey(clazz)) {
                   //实例化当前Initialize组件,并找到依赖的组件,依次执行初始化操作
                                    doInitialize(clazz, initializing);
                                }
                            }
                        }
                      //执行create方法(被依赖的Initialize组件会先执行)
                        result = initializer.create(mContext);
                    } 
                } else {
                    result = mInitialized.get(component);
                }
                return (T) result;
            } 
        }
    }

本人水平有限,如有错误请留言指正。如果本文对你有一点点帮助,请随手点个赞鼓励一下吧