This article launches my wechat public account: Programmer Xu Gong

preface

A while ago, I wrote several articles on Android startup optimization, mainly from two aspects.

  1. How to solve the problem of multithreading task dependency
  2. Home page layout optimization, from the conventional layout nesting optimization to progressive loading, and then to asynchronous loading.

Android Startup Optimization (1) – Directed acyclic graph

Android startup optimization (2) – Topology sort principle and solution ideas

Android startup optimization (III) – AnchorTask open source now

Android Startup Optimization (4) – AnchorTask is implemented

Android Startup Optimization (5) – AnchorTask version 1.0.0 is now available

Android Startup Optimization (VI) – In-depth understanding of layout optimization

After the release of nuggets, several articles have been recommended on the nuggets home page, deep we like, reading is also quite good.

JetPack App Startup is different from AnchorTask, which is open source.

Today, let’s talk about JetPack App Startup.

The catalog looks something like this

1 What is JetPack App Startup 2 What is JetPack App Startup 3 JetPack App Startup App Startup source code analysis 6 summary

What is JetPack App Startup

Let’s take a look at the official explanation, the official address: developer.android.com/topic/libra…

The App Startup library provides a straightforward, performant way to initialize components at application startup. Both library developers and app developers can use App Startup to streamline startup sequences and explicitly set the order of initialization.

Instead of defining separate content providers for each component you need to initialize, App Startup allows you to define component initializers that share a single content provider. This can significantly improve app startup time.

Translation:

  1. App Startup The library provides a component that can be initialized when an application is started.
  2. Developers can use this component to streamline startup sequences and explicitly set the order of initialization.
  3. Instead of defining a separate ContentProvider for each component,App Startup allows all componentization you define to share a single ContentProvider. This can greatly reduce the startup time of high applications

What problem does JetPack App Startup solve

After listening to the above introduction, are you still a little confused?

App Startup reduces Startup time for high-powered applications. How does it work?

For those of you who have done Android startup optimization, you probably know that the startup process of Android looks like this.

From Application#attachBaseContext to contentprovideroncreate to Application#onCreate to mainactivityoncreate.

App Startup is designed to wrap up contentProviders. Many third-party SDKS use the ContentProvider operation so that the user doesn’t have to manually call the SDk #init method.

In the AndroidManifest registered their own xxSDkProvider, and then in the xxSDkProvider onCreate aspect of the initialization, it is true that the caller does not need to initialize themselves, but increased the startup time, if you want to optimize, I also have to remove the initialization of the ContentProvider, is it worth it, I feel it is not necessary, this operation is really beautiful.

<application ... > <provider android:name=".xxSDkProvider" android:authorities="${applicationId}.xxSDkProvider" android:exported="false" /> </application>Copy the code
class XXSDKProvider : ContentProvider() {

    override fun onCreate(): Boolean {
        Log.d(TAG, "XXSDKProvider create()")
        XXSDK.init()
        return true
    }
    
    .....
}

Copy the code

At the same time, this provides an idea for students who do priming optimization. Open your Apk and take a look at how many providers there are in AndroidManiest to see if there are any. If so, change it and maybe start the optimization and cut 100 milliseconds off all at once.

How to use AppStartUp

AppStartUp Basic use

In short, there are three steps

  1. Gradle files are imported into the App Startup library.
  2. Define a custom Initializer for initialization.
  3. Configure the custom Initializer into androidmanifest.xml.

The first step is to add dependencies to the build.gradle file

Dependencies {implementation "androidx. Startup :startup-runtime:1.0.0"}Copy the code

Step 2: Customize the implementation Initializer class

There are two main approaches

  1. T create(@NonNull Context context)Initialize a component and return it to Application
  2. List<Class<? extends Initializer<? >>> dependencies()The current Initializer depends on which Initializers you can use to determine the order in which you want to start

Let’s take an official example

// Initializes WorkManager.
class WorkManagerInitializer : Initializer<WorkManager> {
    override fun create(context: Context): WorkManager {
        val configuration = Configuration.Builder().build()
        WorkManager.initialize(context, configuration)
        return WorkManager.getInstance(context)
    }
    override fun dependencies(): List<Class<out Initializer<*>>> {
        // No dependencies on other libraries.
        return emptyList()
    }
}
Copy the code

WorkManagerInitializer returns a WorkManager that does not need to rely on other initializers and returns emptyList().

If you need to rely on another Initializer, override the Dependencies method and return it. The ExampleLoggerInitializer below depends on WorkManagerInitializer

// Initializes ExampleLogger.
class ExampleLoggerInitializer : Initializer<ExampleLogger> {
    override fun create(context: Context): ExampleLogger {
        // WorkManager.getInstance() is non-null only after
        // WorkManager is initialized.
        return ExampleLogger(WorkManager.getInstance(context))
    }

    override fun dependencies(): List<Class<out Initializer<*>>> {
        // Defines a dependency on WorkManagerInitializer so it can be
        // initialized after WorkManager is initialized.
        return listOf(WorkManagerInitializer::class.java)
    }
}

class  ExampleLogger(val workManager: WorkManager){

}
Copy the code

Step 3: Configure a custom InitializationProvider in AndroidManifest

<provider android:name="androidx.startup.InitializationProvider" android:authorities="${applicationId}.androidx-startup"  android:exported="false" tools:node="merge"> <! -- This entry makes ExampleLoggerInitializer discoverable. --> <meta-data android:name="com.xj.anchortask.appstartup.ExampleLoggerInitializer" android:value="androidx.startup" /> </provider>Copy the code

It has a fixed format, and the configurator only needs to configure name in meta-data. The android: name = “com. Xj. Anchortask. Appstartup. ExampleLoggerInitializer” the name here is our custom, Initializer the full path.

When the program runs, you can see the following output, which meets our expectations

2021-04-17 17:48:42.049 28059-28059/com.xj. anchorTask I/AnchorTaskApplication: attachBaseContext: 2021-04-17 17:48:42.077 anchorTask I/AnchorTaskApplication: create: WorkManagerInitializer init 2021-04-17 17:48:42.077 28059-28059/com.xj. anchorTask I/AnchorTaskApplication: create: ExampleLoggerInitializer init 2021-04-17 17:48:42.084 28059-28059/com.xj. anchorTask I/AnchorTaskApplication: onCreate:

AppStartUp advanced use

Manual initialization

AppStartUp: ExampleLoggerInitializer Application onCreate: ExampleLoggerInitializer Application onCreate

It’s actually quite simple,

  1. The first step is to remove it in the AndroidManifest InitializationProvider<meta-dataThe label
  2. Call the AppInitializer initializeComponent method in the code to initialize
<provider android:name="androidx.startup.InitializationProvider" android:authorities="${applicationId}.androidx-startup"  android:exported="false" tools:node="merge"> </provider>Copy the code
AppInitializer.getInstance(context).initializeComponent(ExampleLoggerInitializer::class.java)
Copy the code

App Start up source code analysis

Let’s look at its structure first, just a few simple classes

Initializer interface is not necessary, it is very simple, only two methods.

InitializationProvider inherits ContentProvider, taking advantage of the fact that ContentProvider will execute before Application onCreate. To perform some initialization.

public final class InitializationProvider extends ContentProvider { @Override public boolean onCreate() { Context context = getContext(); if (context ! = null) { AppInitializer.getInstance(context).discoverAndInitialize(); } else { throw new StartupException("Context cannot be null"); } return true; } -}Copy the code

We can see that the AppInitializer discoverAndInitialize method is called in the onCreate method.

  1. Find the Meta note under AndroidManifest InitializationProvider
  2. Check whether the value in the meta note is androidx.startup
  3. Check whether the Initializer interface is implemented. If so, perform the doInitialize method
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; String startup = mContext.getString(R.string.androidx_startup); // Find metadata tag if (metadata! = null) { Set<Class<? >> initializing = new HashSet<>(); Set<String> keys = metadata.keySet(); for (String key : keys) { String value = metadata.getString(key, null); Androidx. startup // Check whether the Initializer interface is implemented. If so, reflection initializes 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)); } doInitialize(component, initializing); } } } } } catch (PackageManager.NameNotFoundException | ClassNotFoundException exception) { throw new StartupException(exception); } finally { Trace.endSection(); }}Copy the code

DoInitialize method

<T> T doInitialize( @NonNull Class<? extends Initializer<? >> component, @NonNull Set<Class<? >> initializing) { synchronized (sLock) { boolean isTracingEnabled = Trace.isEnabled(); try { if (isTracingEnabled) { // Use the simpleName here because section names would get too big otherwise. Trace.beginSection(component.getSimpleName()); } if (initializing.contains(component)) { String message = String.format( "Cannot initialize %s. Cycle detected.", component.getName() ); throw new IllegalStateException(message); } 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)) { doInitialize(clazz, initializing); } } } if (StartupLogger.DEBUG) { StartupLogger.i(String.format("Initializing %s", component.getName())); } result = initializer.create(mContext); if (StartupLogger.DEBUG) { StartupLogger.i(String.format("Initialized %s", component.getName())); } initializing.remove(component); mInitialized.put(component, result); } catch (Throwable throwable) { throw new StartupException(throwable); } } else { result = mInitialized.get(component); } return (T) result; } finally { Trace.endSection(); }}}Copy the code

It can be seen that during initialization, the dependency is checked first, and if so, the dependency is initialized first

summary

  • App start up, I think its original design should be to close up the ContentProvider, actually not very helpful for startup optimization.
  • If your project is initialized synchronously and uses multiple ContentProviders, App Startup may have some room for optimization. After all, it is unified in one ContentProvider and supports simple sequential dependencies.
  • There are a lot of SDKS that do this, like the FaceBook Advertising SDK, ummon SDK, etc. When we start optimization, can we remove the corresponding ContentProvider to reduce the time to create the Provider
  • In actual projects, most of them will use multi-thread asynchronous loading, so App start up is useless

See blog: New member of Jetpack, App Startup

This article is available at github.com/gdutxiaoxu/… “Android Learning + Interview Guide” covers the core knowledge most Android programmers need to master. To prepare for an Android interview, choose AndroidGuide! Wechat official account: Xu Gong, programmer