Andorid performance optimization (6) startup speed optimization

1 App startup method

App startup can be divided into: cold start, warm start and hot start. Among them, cold start is the longest startup time for App startup. Today we will explain the optimization of startup speed also for cold start.

1.1 Cold start

When the App starts, there is no process corresponding to the App in the background, such as running the App for the first time after the phone is started, the system memory is tight, causing the App process to be restarted after Kill is dropped, or the user actively ends the App process. This situation means that the system needs to create a new process to assign to the App, and the App needs to go through the initialization process. Cold start is the longest time to start App startup.

1.2 Warm start

The App process is alive, but the current Activity no longer exists. For example, for some reasons, the App was switched to the background, and the Activity may be recycled because of insufficient memory. At this time, starting the App does not need to re-create the process, but the Activity needs to re-create the object.

1.3 Hot start

The App process is alive, and the current Activity object still exists in memory and is not recycled. No need to re-create Activity and initialization. For example, press the Home or Task button to leave the App to do other things, and then quickly return to the situation on the App just now.

 

2 Optimization ideas

We learned in the previous article "Detailed Explanation of Android Application Startup (1) Android System and Android Application Startup Process" that the startup of an App from startActivity to ActivityThread.main () is what the system does and we cannot intervene , And after the process of creating the App , some source code analysis in the article "Detailed Explanation of Android Application Startup (2) The Startup Process of Application and Activity" can probably be understood that the process is to create Application object and the first Activity object Do some corresponding initialization work and the process of callback life cycle method. After the Activity is up, it creates the Window, loads the View, and completes the first drawing. When the App finishes drawing for the first time, it will cut the black and white background instead, showing the interface with the user.

Therefore, we have to optimize the startup speed. The starting point is positioned in the Application initialization process, after the Activity is created, to the display view process, and the View drawing process. In these processes, avoid intensive and heavy events. In other words, it is necessary to optimize the application's attachBaseContext, onCreate; Activity's onCreate, onStart, onResume; interface layout.

 

3 Optimization strategy

3.1 Asynchronous loading / delay loading

The preloading of some data should be placed in an asynchronous thread as much as possible. After the data is loaded, if necessary, it will be notified through the callback callback.

Delayed loading means that the main points are loaded first, and the rest of the points that are not necessary for the first time can be postloaded using postDelayed to achieve the effect of allowing users to quickly see the main functions.

Typical scenarios are:

1 Initialization of third-party SDK

Many times, we will load some third-party SDK to the AttachBaseContext or onCreate of the Application, which is also the culprit to increase the startup time of the Application, so we should try to avoid the synchronization initialization operation in the AttachBaseContext or onCreate of the Application. A better solution is to first analyze whether the SDK is necessary for the first time, and if it is not, then load it with delay or when it is really used.

2 MultDex subcontracting situation

In today's increasingly complex App functions, MultiDex is almost inevitable, and the startup speed of mobile phones before 5.0 is simply a nightmare. In order to optimize the startup speed, you can use the multiDexKeepProguard or multiDexKeepFile attribute to configure the specified class to stay in the main dex file when you configure the subcontracting in the Gradle script. Consider placing MultiDex.install (this); in an asynchronous thread to execute, but it must be handled well before loading is complete, to ensure that the classes in classes2.dex will not be called in advance. For the use of MultiDexKeepProguard or multiDexKeepFile attribute of MultiDex, please refer to the previous article "Detailed Explanation of the Use of Android Gradle (6) How to Solve the 65535 Method Limit" .

3 Use ViewStub to load the interface on demand

Sometimes some Views are not always displayed on the interface, but only displayed to the user under certain conditions. Just like a View with a wrong request, it will not appear at all under the normal process, that is, it is not necessary to let it go. load. So in this scenario, you can use ViewStub to deal with it. ViewStub is very lightweight and has a width and height of 0, and it does not participate in any layout and drawing process itself, which means that it loads the required layout files on demand.

4 Execute logic after the first frame is displayed

The activity of the first screen should be simplified as much as possible, or start to do things after the first frame is drawn, such as the code:

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 第一帧显示后执行
        getWindow().getDecorView().post(new Runnable() {
            @Override
            public void run() {
                mHandle().post(...);
            }
        });
    }
}

Here to explain, getDecorView () returns the root view DecorView object, because DecorView inherits from View, so the post method here will be called to the Post method of View, because the View will be added to the onResume Window, so the Post method here just encapsulates the Runnable into a HandlerAction object and stores it in the ArrayList. When executed to the executeActions method (the executeActions method is executed in the performTraversals method, the View measures / layout / draw process, each frame When drawing is performed by the performTraversals method, there will be a HandlerAction here and then the Handler object passed in through the executeActions method to re-post. So this Post's runnable object was finally added to the MessageQueue of MainLooper when the first performTraversals method was executed.

3.2 Simplified layout

Regarding the optimization of the layout, we have already introduced the "interface layout optimization" in the previous article "Andorid Performance Optimization (1) How to Optimize the Memory for the App" , and I will not repeat it here.

3.3 Eliminate black and white screen

The reason for the black and white screen is actually that when the Activity is started, the window background will be loaded before setContentView. The system will set the window background to white or black by default. When the App starts too slowly, you will see a black and white screen. So in this case, if you want to eliminate the black and white screen, you can add a lightweight Splash page when the app starts. Eliminating black and white screens is not a speed-optimized solution, but it can improve the user experience.

 

4 Method of evaluating start-up speed

4.1 display time

Starting from Android 4.4 version, Logcat will output the time it takes for each Activity to be displayed on the interface. This method is more suitable for measuring the start time of the program. As shown:

4.2 Use startMethodTracing () and stopMethodTracing ()

We only need to add startMethodTracing start and stopMethodTracing end to the time-consuming code segment to analyze the time-consuming situation of each method in the process through the generated trace file, such as:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Debug.startMethodTracing("test");
        test();
        test2();
        Debug.stopMethodTracing();
    }

    private void test() {
        try {
            Thread.sleep(4);
        } catch ( Exception ex) {
            ex.printStackTrace();
        }
    }

    private void test2() {
        try {
            Thread.sleep(3);
        } catch ( Exception ex) {
            ex.printStackTrace();
        }
    }
}

In this way, after the program runs, a test.trace file will be generated in the Android / data / app package name / files directory. Open the trace file through Android Studio to analyze the time used by each method in the code process, as follows Figure:

4.3 Start App calculation time through adb command

Use the adb command: adb shell am start -W packageName / packageName.activity, you can start the specified Activity of the App, and you can view its startup time, such as:

WaitTime represents the total time spent, including the time of the previous application Activity pause and the time of the new application startup;

ThisTime represents the start-up time of the last Activity that starts a series of activities;

TotalTime represents the time spent starting a new application, including the start of a new process and the start of an Activity, but does not include the time spent by the previous application Activity pause.

Phones before Android 5.0 do not have the value of WaitTime. Generally, we only need to care about TotalTime. This time is the time spent by the application itself to start.

 

 

Published 106 original articles · praised 37 · 80,000 views

Guess you like

Origin blog.csdn.net/lyz_zyx/article/details/88246224