1. Introduction As the project version iterates, the performance problems of the App will gradually be exposed, and a good user experience is closely related to performance. Starting from this article, I will start a special topic on Android application performance optimization, from theory to practice, from entry to deep digging, and practice performance optimization in the project step by step. Welcome to continue to pay attention! So in the first article, I will start with the application startup optimization, and create a lightning-fast App startup speed based on actual cases. 2. Introduction to startup acceleration Let’s take a look at the official Google document “Launch-Time Performance” (https://ldeveloper.android.com/topic/performance/launch-time.html) for an overview of application startup optimization; Application startup can be divided into cold startup, hot startup, and warm startup. The slowest and most challenging startup is the cold startup: the system and the App itself have more work to do from scratch! Before the application is cold started, it must perform three tasks:
After these three tasks are completed, the following tasks will be executed immediately:
Once the App process completes the first drawing, the system process will replace the displayed Background Window with the Main Activity, and the user can then use the App. As a common application, we cannot actively control the creation of the App process. What we can optimize are the processes of Application, Activity creation and callback. Similarly, Google also gave directions for starting acceleration:
Note: Direction 1 is a temporary solution and only appears faster on the surface; Directions 2 and 3 can actually speed up the startup. Next we will apply it in the project. 3. Startup acceleration theme switching According to the official documentation: Use the windowBackground theme attribute of Activity to provide a simple drawable for the launched Activity. Layout XML file: Manifest file: In this way, when starting up, an interface will be displayed first. This interface is the Style set in the Manifest. After the Activity is loaded, the Activity interface will be loaded. In the Activity interface, we reset the theme to the normal theme, which creates a sense of speed. However, as summarized above, this method does not really speed up the startup process, but optimizes the display effect through interactive experience. Note: The screenshots are also from the official document "Launch-Time Performance". 4. Startup acceleration: Avoid Heavy App Initialization Through code analysis, we can get the business workflow diagram started by App: In this chapter, we focus on the initialization part: in Application and the first screen Activity, we mainly do the following:
In the project, except for Tingyun, all other third-party components take the lead and are initialized in the main thread of Application. This initialization method is definitely too heavy:
Project Modifications:
Note: The 2-second pause of the splash screen page can be used to delay time-consuming operations to this time interval. 5. Diagnosing the Problem In this section, we actually locate the time-consuming operations. In the development stage, we usually use BlockCanary or ANRWatchDog to find time-consuming operations. It is simple and clear, but it cannot get the execution time of each method and more detailed comparison information. We can use Method Tracing or DDMS to obtain more comprehensive and detailed information. Start the application and click Start Method Tracing. Click it again after the application starts. It will automatically open the .trace file recorded by the previous operation. It is recommended to use DDMS to view it, which is more convenient and comprehensive. The left side shows the specific thread where the call occurred, the right side shows the timeline where the call occurred, and below that is the specific method where the call occurred. Note the two columns: Real Time/Call (actual time of occurrence), Calls+RecurCalls/Total (number of occurrences); From the above figure we can get the following information:
Even if it is a time-consuming operation, as long as it happens correctly in WorkThread, there is no problem. Therefore, we need to confirm the threads in which these methods are executed and when they occur. If these operations occur in the main thread, they may not constitute the conditions for the occurrence of ANR, but jamming is inevitable! Combining the business operations and analysis diagrams in the App cold start business workflow diagram in the previous chapter, we can see from the code again that some time-consuming operations such as IO reading do occur in the main thread. In fact, clicking the name of the execution function in traceview can not only track the time-consuming methods of the parent and child classes, but also see which thread is in the method execution timeline and the time-consuming interface flashes. After analyzing that some time-consuming operations occur in the main thread, will everything be fine if we move all the time-consuming operations to the child thread? No!! The lag cannot be solved by asynchrony. Incorrect use of engineering threads will not only fail to improve the lag, but may aggravate it. Whether to enable the working thread needs to be analyzed according to the specific root cause of the performance bottleneck, and the right remedy cannot be generalized; How to start a thread is also a science: Thread, ThreadPoolExecutor, AsyncTask, HandlerThread, IntentService, etc. all have their own advantages and disadvantages; for example, ThreadPoolExecutor is usually more efficient and has obvious advantages than Thread, but in a specific scenario, Thread will perform better than ThreadPoolExecutor at a single point in time: for the same object creation, the overhead of ThreadPoolExecutor is significantly greater than that of Thread; Correctly starting a thread is not a cure-all. For example, executing a network request will create a thread pool, and correctly creating a thread pool in the Application will inevitably slow down the startup speed; therefore, delayed operations are also essential. Through detailed tracking of traceview and detailed comparison of the code, I found that the jam occurred in:
And other details:
Project Modifications: 1. Move database and IO operations to the worker thread, and set the thread priority to THREAD_PRIORITY_BACKGROUND. This way, the worker thread can get a maximum of 10% of the time slice, giving priority to the main thread. 2. Process sorting and delayed execution; In fact, this step is the most effective in accelerating the project launch. Through process analysis, it is found that some processes are called too early or have errors, such as: Update and other operations do not need to be called before the first screen is displayed, causing resource competition; The switch made by IOS to circumvent audit was called, resulting in intensive network requests; Our own statistics show that a fixed number of 5 thread pools are created in the Application call, causing resource competition. In the last line of the traceview function description in the above figure, we can see that number 12 is executed 5 times, ranking first in terms of time consumption; the creation of the thread pool here is necessary but can be postponed. Modify the ad splash screen logic to take effect next time. 3. Other optimizations;
Through the above three steps and the optimization of the third-party components: the main thread does not waste time or compete for resources during the callback of the Application and the first screen Activity. In addition, some technologies such as layout optimization and memory optimization are also involved. Since cold start of an application is generally not a bottleneck, we will not discuss them in detail here and can deal with them according to the actual project. 6. Contrast effect: Use the ADB command to count the application startup time: adb shell am start -W first screen Activity. Under the same conditions, MX3 and Nexus 6P were used to start up 5 times, and the startup time before and after optimization was compared; Before optimization: MX3 Nexus 6P After optimization: MX3 Nexus 6P contrast: MX3 improved by 35% Nexus 6P improved by 39% Command meaning:
7. Question: 1. What directions can be further optimized?
2. What is the basis for asynchronous and delayed initialization and operation? Note: Not every component initialization and operation can be asynchronous or delayed; whether it can be done depends on the calling relationship of the components and the specific business needs of your own project. Follow one rule: asynchronous what can be done asynchronously, and delay what cannot be done asynchronously as much as possible. Start the application first, then operate. 3. General application startup acceleration routine?
4. Others
|
>>: After disassembling the iPhone 11 Pro Max, they discovered these secrets
Data analysis is difficult, as difficult as climb...
[[152058]] According to the online version of the...
The golden snub-nosed monkey is a very famous rar...
Northwest Europe is at the forefront of low-emiss...
In the "Fortune World's Top 500 Companie...
Last week a number of publications broke the stor...
On October 31, my country's floating wind-fis...
Yan Jie's 36 Fat Burning and Fast Slimming Me...
[[147453]] After you've been coding for a whi...
In recent decades, scientists have come to unders...
Sichuan Mustang sued Ford Mustang for trademark i...
People often ask: "What good marketing metho...
Tencent products, a high-quality performance mark...
Narrative Change Training Camp: From Passive to A...
Fission is a very popular concept this year, on p...