preface

Before, we talked about some common methods for starting optimization, but some people are not very impressed:

“These methods have been known for a long time. Don’t you want to say something new? Like App Startup? Will it help with startup optimization?”

Ok, since your sincere heart of the question, that I show great compassion to tell you: an also do not know 😢.

Go ahead and take a look at this App Startup. Is it really going to optimize your Startup?

(If you want to see the results, you can skip to the final practice and summary stage.)

Init in the Contentprovider

As you all know, many tripartite libraries need to be initialized in the Application and get the context of the Application incidentally.

But there are libraries that don’t need to be initialized by ourselves, that are initialized by stealth, by using ContentProvider, defining a ContentProvider, and then getting the context in onCreate, and then doing the initialization of the library itself. One step in the APP startup process is to execute the onCreate method of all registered ContentProviders in the APP, so the initialization of the library is silently completed.

This is a great convenience for developers of integrated libraries. Many libraries now use this method, such as Facebook and Firebase. Here is an example of Facebook’s ContentProvider:

    <provider
        android:name="com.facebook.internal.FacebookInitProvider"
        android:authorities="${applicationId}.FacebookInitProvider"
        android:exported="false" />
Copy the code
public final class FacebookInitProvider extends ContentProvider {
    private static final String TAG = FacebookInitProvider.class.getSimpleName();

    @Override
    @SuppressWarnings("deprecation")
    public boolean onCreate(a) {
        try {
            FacebookSdk.sdkInitialize(getContext());
        } catch (Exception ex) {
            Log.i(TAG, "Failed to auto initialize the Facebook SDK", ex);
        }
        return false;
    }

    / /...
}
Copy the code

As you can see, in the Facebook Book SDK, a FacebookInitProvider is defined and initialized in onCreate. That’s why we don’t need to initialize Facebook’s SDK separately.

This is more convenient, but does this have any benefit to boot optimization? Let’s review the previous start-up process again.

  • .
  • attachBaseContext
  • Application attach
  • installContentProviders
  • Application onCreate
  • Looper.loop
  • The Activity onCreate, onResume

The installContentProviders method starts and executes the onCreate method of each ContentProvider before the onCreate method of the Application.

So these libraries just move the tripartite library initialization of the Application forward into the ContentProvider, which increases the startup time rather than reducing it.

How can I put it? Because different libraries define different ContentProvider classes, there are so many contentProviders. As one of the four components, ContentProvider is time-consuming to start, which naturally increases the time consumed in App startup.

App Startup is needed to optimize this situation

Website profile,

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.

There are two main features:

  • You can share a single Contentprovider.
  • You can explicitly set the initialization order.

You can share a single Contentprovider

Instead of launching multiple contentProviders, different libraries share the same Contentprovider.

This will at least not increase the startup time.

How do you do that? If you are a FacebookSDK designer, you will be able to integrate App Startup with FacebookSDK.

/ / import library
implementation "Androidx. Startup: startup - runtime: 1.0.0"


// Initializes facebooksdk.
class FacebookSDKInitializer : Initializer<Unit> {
    private  val TAG = "FacebookSDKInitializer"

    override fun create(context: Context): Unit {
        try {
            FacebookSdk.sdkInitialize(context)
        } catch (ex: Exception) {
            Log.i(TAG, "Failed to auto initialize the Facebook SDK", ex)
        }
    }

    
    override fun dependencies(a): List<Class<out Initializer<*>>> {
        return emptyList()
    }
}


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

    <meta-data  android:name="com.example.FacebookSDKInitializer"
          android:value="androidx.startup" />
</provider>
Copy the code

Implementing the Initializer interface and then initializing it in the onCreate method can reduce startup time as long as all libraries follow this standard instead of customizing their own ContentProvider.

The Tools :node=” Merge “tag is used to merge all contentProviders that declare InitializationProvider.

The Initializer interface also has a method called Dependencies.

You can explicitly set the initialization order

This is the second feature of App Startup. You can set the initialization order.

As you can imagine, in accordance with the above approach, all libraries are set in this way, then will be in the same ContentProvider is androidx. Startup. InitializationProvider initialization, but if I need to set different library initialization order?

For the Facebook initialization described above, I need to set it to run after another library, WorkManager, so we can rewrite the Dependencies method:

class FacebookSDKInitializer : Initializer<Unit> {
    private  val TAG = "FacebookSDKInitializer"

    override fun create(context: Context): Unit {
        try {
            FacebookSdk.sdkInitialize(context)
        } catch (ex: Exception) {
            Log.i(TAG, "Failed to auto initialize the Facebook SDK", ex)
        }
    }

    
    override fun dependencies(a): List<Class<out Initializer<*>>> {
        return listOf(WorkManagerInitializer::class.java)
    }
}
Copy the code

After this setting, the initialization order of the tripartite library becomes:

WorkManager Initialization -> FacebookSDK initialization.

Practice leads to truth

Having said that, in theory, it is true that App Startup reduces time, after all, multiple content providers are merged into one, so we believe that “practice is the only criterion for testing truth”, let’s practice to see how much time is reduced.

How do I count this startup time? Generally, there are the following schemes:

  • If it is the time of Application and Activity, you can count the time through TraceView, Systrace, etc., but the initialization of ContentProvider before Application is not applicable to our practice this time.

  • Android Vitals provides a tool to measure the startup time of online apps. It displays the startup time of apps that have been launched for too long in the GooglePlay admin center. Obviously, this doesn’t work for us either.

  • Video recording. If it is an offline APP, we can accurately measure the startup time by video recording. That is, we can determine the startup time of the app by judging each frame of the video, and then count the startup time. Use adb shell screenrecord command to make a screenrecord and then analyze the video.

  • Finally, use the system TotalTime.

This time is calculated for us in the Android source code, which can count the start time of the Activity. If we run the command in the Home page, we can also get a cold start time. Although this time is not very accurate, I only need to compare the size of the time before and after the use of App StartUp, so it is enough. Start drying.

1) Test two ContentProviders

The first time, we tested two contentProviders.

        <provider
            android:name=".appstartup.LibraryAContentProvider"
            android:authorities="${applicationId}.LibraryAContentProvider"
            android:exported="false" />

        <provider
            android:name=".appstartup.LibraryBContentProvider"
            android:authorities="${applicationId}.LibraryBContentProvider"
            android:exported="false" />
Copy the code

After the installation, open the application and enter the command in Terminal:

adb shell am start -W -n packagename/packageName.MainActivity

Since each startup time is different, we run it five times and take the average:

TotalTime: 927
TotalTime: 938
TotalTime: 948
TotalTime: 934
TotalTime: 937Average:936.8
Copy the code

Then comment out the ContentProvider registration code, add the App Startup code and register:

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

            <meta-data  android:name="com.example.studynote.appstartup.LibraryAInitializer"
                android:value="androidx.startup" />

            <meta-data  android:name="com.example.studynote.appstartup.LibraryBInitializer"
                android:value="androidx.startup" />
        </provider>
Copy the code

Run the App and run the command to get the startup time:

TotalTime: 931
TotalTime: 947
TotalTime: 937
TotalTime: 940
TotalTime: 932Average:937.4
Copy the code

Yi?? Is my phone broken? Why didn’t it go the way I expected, and it took longer?

There are two contentProviders, and App startup is used to integrate them into one.

In fact, this involves the actual time consuming of ContentProvider. I found a graph on the Internet, which is the official statistics made by Google about the time consuming of ContentProvider. The picture comes from Guo Shen’s blog:

It can be seen that one ContentProvider takes about 2ms and 10ContentProvider takes about 6ms.

So we only reduced the time spent on one ContentProvider, which is negligible. In addition, some tasks of the InitializationProvider in the App Startup library we used will also take time, such as:

  • Will go through all of themmetadataComponent of the tag
  • Each component is retrieved by reflectionInitializerInterface, and get the corresponding dependencies, and proceedThe sorting.

These operations are also time consuming, which is increased by integrating the App Startup library. It is possible that the above situation will occur, and the Startup time will increase after integrating the App Startup library.

Does that make the library useless? Definitely not. It’s useful when there are more and more ContentProviders. Try 10 more contentProviders.

2) 10 ContentProviders

Create 10 contentProviders and register them in androidmanifest.xml:

        <provider
            android:name=".appstartup.LibraryAContentProvider"
            android:authorities="${applicationId}.LibraryAContentProvider"
            android:exported="false" />

<! -- Omit the remaining 9 provider registration codes -->
Copy the code

Run five times and take the average value:

TotalTime: 1758
TotalTime: 1759
TotalTime: 1733
TotalTime: 1737
TotalTime: 1747Average:1746.8
Copy the code

Then comment out the ContentProvider registration code, add the App Startup code and register:

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

            <meta-data  android:name="com.example.studynote.appstartup.LibraryAInitializer"
                android:value="androidx.startup" />

            <! -- Omit the remaining 9 meta data registration code -->
        </provider>
Copy the code

Run the App and run the command to get the startup time:

TotalTime: 1741
TotalTime: 1755
TotalTime: 1722
TotalTime: 1739
TotalTime: 1730Average:1737.4
Copy the code

Before using App Startup, the Startup time is 1746.8ms, and after using App Startup, the Startup time is 1737.4ms, reduced by 9.4ms.

Therefore, it is concluded that when the integrated library uses a certain number of contentProviders, it can indeed reduce the time, but not much. For example, here we have 10 ContentProviders integrated with App Startup, the time can be reduced by about 10ms. Combined with the official statistics in the figure above, generally a project integrates more than a dozen libraries using ContentProvider, and the time reduction should be within 20ms.

So our App Startup addresses that. It’s not much, but it does have features to reduce that time.

thinking

Although this library can solve certain problems of three-party library initialization time, I think it still has some limitations, such as these:

  • Not many libraries depend on themselves. If our project itself has few dependencies, is it necessary to integrate this? In extreme cases, if you rely on only one library, then providing an InitializationProvider adds time.
  • Delayed initialization. As we said last time, some libraries don’t need to be initialized initially, so it’s best to lazily initialize them and load them lazily.
  • Asynchronous initialization. Also, libraries that do not need to be initialized on the main thread can be initialized asynchronously to reduce startup time.
  • Multiple asynchronous task dependencies. What if some tasks need to be executed asynchronously and have dependencies on each other?

What is the solution to this problem?

  • No, you can say yes, it’s closedApp StartupAnd then perform initialization task management yourself.

This is not a joke. App Startup aims to solve a single problem, namely the creation of multiple contentProviders. So it should be used for each third-party library designer. When you design a library, if you want to initialize it silently, you can use App Startup. When as many libraries as possible comply with this requirement and are connected to App Startup, the developer’s Startup time is naturally reduced.

However, if we have other requirements, such as delayed initialization, asynchronous initialization and other problems mentioned above, we need to close the App Startup function of some libraries or all libraries, and then independently initialize tasks, such as handling the relationship between each initialization task through the initiator.

If a library already integrates App Startup functionality, how do we turn it off? This is done using the Tools :node=”remove” tag.

<! -- Disable all InitializationProvider component initializations -->
<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    tools:node="remove" />


<! -- Disable a single InitializationProvider component initialization -->
<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    android:exported="false"
    tools:node="merge">

    <meta-data  android:name="com.example.FacebookSDKInitializer"
            android:value="androidx.startup"
            tools:node="remove"/>
</provider>
Copy the code

This way, the FacebookSDK doesn’t initialize automatically, requiring us to call the initialization method manually.

conclusion

1) App Startup is designed to solve a problem:

  • That is, different libraries use different ContentProviders for initialization, resulting in too many ContentProviders, messy management, and time-consuming problems.

2) How much time can App Startup save?

  • If 20 or 30 libraries are integrated with App Startup, the time saved will be less than 20ms.

3) App Startup:

  • For tripartite library designers or componentized scenarios. When you design a library or a component, you can tap into App Startup. When as many libraries as possible follow this standard and are connected to App Startup, a specification is formed and the Startup time of the App is naturally reduced.

4) If you want to solve the startup time problem caused by too many initialization tasks of multiple libraries:

  • Please turn left to various initiators such as Alibaba/Alpha

reference

Google docs

App Startup – Guo Lin

Android startup time – siYU8023

App Startup source code — Ye Zhichen

Bye bye

Thank you for your reading. If you study with me, you can pay attention to my public account — code on blocks ❤️❤️. Here is a group of Android friends, welcome to join us