1.为什么需要App Startup

When a main project references libraries, some parameters need to be initialized when the libraries are started. There are two methods: one is to inform the user in the document that he/she initializes in the Application of the main project; Alternatively, the library developer initializes the Content Provider itself by creating a new Content Provider (since all Content Provider components are read before entering the main Activity).

2. What is App Startup

It is essentially a Content Provider

3. Why can App Startup(Content Provider) be used for initialization?

Say first conclusion: because the component lifecycle callback execution order is: Application. AttachBaseContext () – > ContentProvider. The onCreate () – > Application. The onCreate ()

3.1 ActivityThread. The main ()

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

// This object is used to pass information between processes
final ApplicationThread mAppThread = new ApplicationThread();

 private void attach(boolean system, long startSeq) {
     final IActivityManager mgr = ActivityManager.getService();
     // An ActivityManagerService object is generated
     mgr.attachApplication(mAppThread, startSeq);
}
Copy the code

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);
}
Copy the code

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) {
    // Send a hander message
    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;
    // The application instance is eventually called, along with the attach method, which then calls the attachBaseContext() method
   app = data.info.makeApplication(data.restrictedBackupMode, null);
  // This instantiates all contentProviders and calls the onCreate() method, notifying AMS to tell other processes
   installContentProviders(app, data.providers);
    // The onCreate() method of application is called
   mInstrumentation.callApplicationOnCreate(app);
}
Copy the code

4. How to use it

The official documentation

5. Why can it be used this way

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

            <! -- Automatic initialization -->
            <meta-data
                android:name="cn.woochen.common_config.LibraryConfig"
                android:value="androidx.startup" />

        <! -- Manual initialization (also lazy initialization) -->
            <meta-data
                android:name="cn.woochen.common_config.LibraryConfig"
                android:value="androidx.startup"
                tools:node="remove" />

</provider>/ / manual initialization process AppInitializer getInstance (context). InitializeComponent (LibraryConfig: : class. Java)Copy the code

Let’s look at automatic initialization

5.1 InitializationProvider. The onCreate ()

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

    void discoverAndInitialize(a) {
        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));
                            }
                            // Add the Initializer component corresponding to the key to the collection
                            doInitialize(component, initializing);
                        }
                    }
                }
            }
        } 
    }
Copy the code

5.2 AppInitializer. DoInitialize ()

Note: Manual initialization is also performed here

    <T> T doInitialize(
            @NonNullClass<? extends Initializer<? >> component,@NonNullSet<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)) {// Instantiate the current Initialize component, find the dependent components, and perform the initialization in turndoInitialize(clazz, initializing); }}}// Execute the create method (dependent Initialize components execute first)result = initializer.create(mContext); }}else {
                    result = mInitialized.get(component);
                }
                return(T) result; }}}Copy the code

My level is limited, if there is an error, please leave a message. If this article has helped you at all, please give it a thumbs up