Detailed explanation and use of Android JetPack startup optimization StartUp initialization components

1. Background

 First look at the Android system architecture diagram

        In an Android device, the device is first powered on (PowerManager), and then the kernel layer is loaded. After the kernel is finished, it starts to check the hardware and the public interface provided for the hardware, and then enters the loading of the library. After the library is mounted, the Init process is initialized and init.rc is called. Next is the initialization of the Zygote process, the core module of the Android system. These start to go to the Framework layer. Zygote will fork various processes, AMS, WMS, Handler, etc., and AMS, WMS and other services will be stored by SystemService, through SystemServiceManager To manage, the MainThread main process will also be created in the Zygote process. When creating various services, these services also provide binders, so that they can communicate with these services.

        Why use this picture to analyze the Android system? That's because we are familiar with the entire startup process so we can use this framework better and complete component loading simply and efficiently.

2. Common Loading Mechanisms in Application

        In the normal development process, in order to survive in the application for a long time, the module will preempt the entry of the application in advance. In application, it is more common to execute directly in the oncreate method. Because the APP starts, there is AMS or ATMS to complete the creation of the application (this is why the Android system architecture is introduced above). The correct time-consuming for the first startup should be from attachBaseContext() to the completion of the first Activity's onResume(). Such a loading mechanism, running in the main thread, will cause another problem, that is, the lag and the startup time are too long.

        In response to this problem, Google provides a startup library to implement a simple and efficient method of initializing components when the application starts.

3. StartUp component

The startup library implements a simple and efficient way to initialize components when the application starts. The App Startup library allows simple and efficient initialization of components at app startup. Both library developers and application developers can use App Startup to simplify the startup sequence and explicitly set the initialization order.

 dependent library

implementation 'androidx.startup:startup-runtime:1.1.1'

Code library:

        The core ones are shown in the classes in the breadboard above. Any node that needs to be initialized needs to implement the interface of Initializer.

public interface Initializer<T> {

    /**
     * Initializes and a component given the application {@link Context}
     *
     * @param context The application context.
     */
    @NonNull
    T create(@NonNull Context context);

    /**
     * @return A list of dependencies that this {@link Initializer} depends on. This is
     * used to determine initialization order of {@link Initializer}s.
     * <br/>
     * For e.g. if a {@link Initializer} `B` defines another
     * {@link Initializer} `A` as its dependency, then `A` gets initialized before `B`.
     */
    @NonNull
    List<Class<? extends Initializer<?>>> dependencies();
}

  1. oncreate: All operations required to initialize the component and return an instance of T.
  2. dependencies: Dependencies, if the current component depends on other components when it is initialized, just add other initialization items. (That is, the Initializer needs to be initialized before creating itself)

case:

class MyInitializer(): Initializer<Boolean> {

    override fun create(context: Context): Boolean {


        Log.e("init","create-A")
       

        return true
    }

    override fun dependencies(): MutableList<Class<out Initializer<*>>> {

        Log.e("init","dependencies-A")
        return mutableListOf()
    }
}

Start StartUp

There are two cases to start startUp, one is automatic and the other is manual.

  1. automatic:

        <provider
            android:name="androidx.startup.InitializationProvider"
            android:authorities="${applicationId}.androidx-startup"
            android:exported="false"
            tools:node="merge">
            <meta-data
                android:name="com.example.wiik.testdemo.startup.MyInitializer"
                android:value="androidx.startup" />

        </provider>

provider: Add the provider of startUp.

<meta-data>: is the object class we initialized

Execute as follows:

 The autocomplete actually calls

AppInitializer.getInstance(context).discoverAndInitialize();

    void discoverAndInitialize() {
        try {
            Trace.beginSection(SECTION_NAME);
            ComponentName provider = new ComponentName(mContext.getPackageName(),
                    InitializationProvider.class.getName());
            ProviderInfo providerInfo = mContext.getPackageManager()
                    .getProviderInfo(provider, GET_META_DATA);
            Bundle metadata = providerInfo.metaData;
            discoverAndInitialize(metadata);
        } catch (PackageManager.NameNotFoundException exception) {
            throw new StartupException(exception);
        } finally {
            Trace.endSection();
        }
    }

  1. Manually call:

Manual call also needs to register provider and add meta-data element, but manual call needs to add a new node,

tools:node="remove"

Application 1: Apply under the meta-data node, then only the init object of this meta-data is manual, and the others are completed automatically

Application 2: Apply under the provider node, then all nodes under the provider node are manually created when needed

        <provider
            android:name="androidx.startup.InitializationProvider"
            android:authorities="${applicationId}.androidx-startup"
            android:exported="false"
            tools:node="merge">
            <meta-data
                android:name="com.example.wiik.testdemo.startup.MyInitializer"
                android:value="androidx.startup" />
            <meta-data
                android:name="com.example.wiik.testdemo.startup.HandInitializer"
                android:value="androidx.startup"
                tools:node="remove" />


        </provider>

Manually call:

boolean flag = AppInitializer.getInstance(this).initializeComponent(HandInitializer.class);
Log.e("init","hand return value="+flag);

The log is as follows:

1. In the process of starting, if there are automatic and manual, then start the automatic first, and then start the manual.

2. If your application has a return value during the init phase, then automatic initialization cannot be completed and can only be received manually.


3. Depend on dependencies

Dependency is a precondition, which generally needs to be initialized in advance, as follows.

First define a pre-Init object

class ProposeInitializer(): Initializer<Boolean> {

    override fun create(context: Context): Boolean {


        Log.e("init","create-A-ProposeInitializer")
        WorkManager.initialize(context.applicationContext,Configuration.Builder().build());

        return true
    }

    override fun dependencies(): MutableList<Class<out Initializer<*>>> {

        Log.e("init","dependencies-C-ProposeInitializer")
        return mutableListOf()
    }
}

Class that references the pre-Initer

class MyInitializer(): Initializer<Boolean> {

    override fun create(context: Context): Boolean {


        Log.e("init","create-A-AUTO")

        return true
    }

    override fun dependencies(): MutableList<Class<out Initializer<*>>> {
        return mutableListOf(ProposeInitializer::class.java)
    }
}

analyze:

Execution order, A depends on C, execute the dependency of A first, execute the dependency of C, execute the creation of C, and then execute the creation of A

At this time, even if C is in manual mode, it will become automatic.

If C also depends on others, it will traverse others.

Whether it is automatic initialization: isEagerlyInitialized

Determines whether an object is automatic,

  public boolean isEagerlyInitialized(@NonNull Class<? extends Initializer<?>> component) {
        // If discoverAndInitialize() was never called, then nothing was eagerly initialized.
        return mDiscovered.contains(component);
    }

The method of this class will be executed ahead of time in the provider.

Four. Summary

        In this way, we have completed the basic architecture analysis and use of startUp. If you need to use this framework, you can put your own class management in it.   

 Notice:

        If you find that the startup fails, check whether the preconditions are met     

Guess you like

Origin blog.csdn.net/qq36246172/article/details/129199518