This article was first published on the wechat public account “Yugang Said”

Why is your APP so slow to start?

App startup Mode


Cold Start

Cold start refers to when the APP is started for the first time after the phone is started, or when the APP process is killed and started again. It can be seen that the necessary condition for a cold start is that the APP process does not exist, which means that the system needs to create processes and the APP needs to be initialized. Of the three startup methods, cold startup takes the most time and is the most challenging to optimize. Therefore, this article focuses on optimization related to cold start.

Warm Start

The App process exists, and the Activity may be reclaimed due to insufficient memory. The process does not need to be re-created to start the App, but the Activity’s onCrate needs to be re-executed. Scene similar to open Taobao to wander around a circle and then cut to wechat to chat, after half an hour to return to Taobao. At this point, the Taobao process exists, but the Activity may be reclaimed, so you just need to reload the Activity.

Hot Start

The App process exists, and the Activity object is still in memory and has not been reclaimed. Object initialization can be avoided repeatedly, and layout parsing can be drawn. The scenario is similar to that when you open wechat and chat for a while, you go out to look at the calendar.

What is the relationship between locking App in recent tasks and startup mode

Some manufacturers provide the function of locking the APP for user experience, in order to prevent users from killing the locked APP and starting it in cold startup mode. But locking is not a panacea. Low memory killer will kill the locking APP even when memory is extremely tight, and will run in cold startup mode when it starts here.

What does AI have to do with startup

AI has a lot to offer in terms of process management. MIUI10 released the process AI wake up feature, which makes APP start up much faster than friends. The reason for this is simply to learn the user’s usage habits and create the App process well in advance, so that there will be no cold start when users open the App. For example, if you are a heavy user of wechat and you find that you can no longer see the earth on the wechat launch page after using MIUI10, this is the credit of AI Wake up.

The steps needed to go through from clicking the APP icon to the home page display


Here we discuss the process of cold start. In principle, there are four ways to start a process, that is, by calling the four major components of the APP by other processes.

Here we focus on the APP startup after the user clicks on the desktop, which is started by startActivity. Call startActivity, through layer upon layer calls, this method will eventually call ActivityStackSupervisor. In Java startSpecificActivityLocked, when the activity belong process hasn’t started, you need to create the corresponding Cheng.

void startSpecificActivityLocked(.{

    ProcessRecord app = mService.getProcessRecordLocked(r.processName,

            r.info.applicationInfo.uid, true);

    if(app ! =null&& app.thread ! =null) {

.// The process has been created

        return

    }

    // Create process

    mService.startProcessLocked(r.processName, r.info.applicationInfo, true.0.

                "activity", r.intent.getComponent(), false.false.true);

}

Copy the code

The final process is the Zygote Fork process:

After the process starts the system also has a job is: the process starts immediately after the application shows a blank start window.

Once the system creates the application process, the application process takes care of the next stage. The phases are: 1. Create the application object 2. Start the main thread 3. Draw a View. 5. Layout the screen. 6

Once the App process completes its first drawing, the system process replaces the displayed Background Window with the Main Activity, and the user is ready to use the App.

image.png

There are two obvious optimizations:

When the APP starts, a blank startup window remains on the screen until the system has first drawn the APP. At this point, the system process swaps the application’s startup window, allowing the user to begin interacting with the application. If application.onCreate () is overloaded in your Application, the onCreate() method is called. After that, the application generates the main thread (also known as the UI thread) and performs the task by creating the MainActivity.

Optimizing the onCreate() method has the biggest impact on load time because it does the work with the highest overhead: loading and drawing the view, and initializing the objects the Activity needs to run.

Start speed optimization


How do you quantify startup time?

1. The most awesome test I have seen so far is the use of manipulator and high-speed camera. After the mobile phone is turned on, the manipulator clicks the icon on the application desktop, and the high-speed camera records the startup process. This method is the most intuitive and accurate, but it also costs a lot.

2. Run the shell command

adb shell am start -W[packageName]/[packageName.MainActivity]

Copy the code

Three measured times are returned upon successful execution:

ThisTime: Generally the same as TotalTime, unless a transparent Activity is started at app startup to preprocess something and then display the main Activity, which will be smaller than TotalTime.

TotalTime: Application startup time, including process creation, Application initialization, and Activity initialization to screen display.

WaitTime: Generally larger than TotalTime, including time spent on system impact.

3. You can calculate the startup time by adding logs to your code

4. Use systrace

Application OnCrate () optimization

1. Processing of third-party SDK initialization Application is the main entrance of the program, and many third-party SDK sample programs require themselves to perform initialization operations during Application OnCreate. This is the main cause of increasing Application OnCreate time, so it is important to avoid simultaneous initialization during Application OnCreate. A better solution is to lazily load the third-party SDK, not initialize it with Application OnCreate(), and load it when it’s actually needed. Here is an example of ImageLoader optimized for lazy loading.

Normally when we use imageLoader we load it in the main thread at Application onCreate() :

public class MyApplication extends Application {



    @Override

    public void onCreate(a) {

        super.onCreate();

        ImageLoaderConfiguration.Builder config =

                new ImageLoaderConfiguration.Builder(this);

        ImageLoader.getInstance().init(config.build());

    }

}

Copy the code

In this case, run adb shell am start -w [packageName]/[packageName.MainActivity] to check the application startup time and kill the process each time.

Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.luozhanwei.myapplication/.MainActivity }

Status: ok

Activity: com.luozhanwei.myapplication/.MainActivity

ThisTime: 423

TotalTime: 423

WaitTime: 441

Copy the code

Total time is between 423ms. Here is an example of a utility class that encapsulates a lazy loading ImageLoader:

public class ImageUtil {



    private static boolean sInit;



    private synchronized static void ensureInit(a) {

        if (sInit) {

            return;

        }

        ImageLoaderConfiguration.Builder config =

                new ImageLoaderConfiguration.Builder(SecurityCoreApplication.getInstance());

.

        // Initialize ImageLoader with configuration.

        ImageLoader.getInstance().init(config.build());

        sInit = true;

    }



public static void display(String uri, ImageView imageView, boolean cacheOnDisk) {

        imageView.setImageResource(R.drawable.icon_app_default);

        ensureInit();

        ImageLoader loader = ImageLoader.getInstance();

        if (cacheOnDisk) {

            loader.displayImage(uri, imageView);

        } else {

            loader.displayImage(uri, imageView, OPTIONS_NO_CACHE_DISK);

        }

    }

Copy the code

Startup time after using this scheme:

Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.luozhanwei.myapplication/.MainActivity }

Status: ok

Activity: com.luozhanwei.myapplication/.MainActivity

ThisTime: 389

TotalTime: 389

WaitTime: 405

Copy the code

See that TotalTime has been reduced by 34ms (the data given is the average of 10 tests).

Therefore, Application OnCreate avoids doing a lot of time-consuming operations on the main thread, such as IO logic, which can affect Application startup speed. If you have to do it you have to put it in a child thread.

Activity onCreate () optimization

Reduce the View hierarchy of LaunchActivity and reduce the View measurement drawing time. Avoid time-consuming operations on the main thread

User experience optimization

Eliminate white/black screen at startup

Cold start white screen. GIF

Why does a short black or white screen appear during startup? Between the moment the user clicks on your app and the time the system calls Activity.oncreate (), WindowManager will first load the windowBackground in the app theme style as the app preview element. Then load the activity’s layout.

Obviously, if your application or activity starts too slowly and the system’s BackgroundWindow is not replaced in time, you will start with a white screen or a black screen (depending on whether your theme is Dark or Light).

The solution

1. Throw the pan to the system

Using a transparent theme:

<item name="android:windowIsTranslucent">true</item>

Copy the code

Activity.oncreate () before the App does not display, so that users mistakenly think that the phone is slow, such a scheme should not be used.

<resources>



    <! -- Base application theme. -->

    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">

        <! -- Customize your theme here. -->

        <item name="colorPrimary">@color/colorPrimary</item>

        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>

        <item name="colorAccent">@color/colorAccent</item>

        <item name="android:windowIsTranslucent">true</item>

    
</style>



</resources>

Copy the code

The effect is as follows:

Jilt pot. GIF

2. Theme replacement We can customize a Lancher in style and put a background image in it, or an advertisement image, or something like that

<style name="AppTheme.Launcher">

        <item name="android:windowBackground">@drawable/bg</item>

    
</style>

Copy the code

Set this style to the Activity that starts

<activity

            android:name=".activity.SplashActivity"

            android:screenOrientation="portrait"

            android:theme="@style/AppTheme.Launcher"

            >


Copy the code

Then, in the Activity onCreate method, set the Activity back to its original theme

@Override

    protected void onCreate(Bundle savedInstanceState) {

        // Replace with the original theme, called before onCreate

        setTheme(R.style.AppTheme);

        super.onCreate(savedInstanceState);

    }

Copy the code

This prevents the awkwardness of a black-and-white screen by showing the user an image or advertisement at startup.

Welcome to follow my wechat public account “Yugang said” to receive first-hand technical dry goods