First, preface
With the iteration of the project version, the performance issues of the app are gradually exposed, and the good user experience is closely related to performance, starting with this article, I'll start an Android Application Performance optimization topic, from theory to combat, from introductory to deep digging, hands-on performance optimization practice to the project, welcome to continue to pay attention!
So the first article I started with the application start optimization, according to the actual case, to create a lightning-like app startup speed.
Second, initial knowledge start accelerating
Take a look at Google's Official document "Launch-time performance" for an overview of application launch optimization;
Application start-up is divided into cold start, hot start, warm start, and the slowest start, the biggest challenge is cold start: The system and the app itself have more work to start from scratch!
To perform three tasks before the cold boot is applied:
- Load launch app;
- A blank window is displayed immediately after the app is launched.
- The process of creating the app;
When these three tasks are completed, the following tasks are performed immediately:
- Create an App object;
- Start main Thread;
- Create a startup activity object;
- Load view;
- Layout screen;
- for the first draw;
Once the app process finishes the first draw, the system process replaces the displayed background Window with main activity, where the user can use the app.
Apply Cold start flowchart
As a general application, the creation of the app process is not actively controlled, we can optimize the process of application, activity creation and callback.
Similarly, Google gives the direction to start accelerating:
- Use the window shown in advance to quickly display an interface to give users a quick feedback experience;
- Avoid heavy initialization at startup (Heavy app initialization);
- Positioning problems: Avoid I/O operations, deserialization, network operations, layout nesting, etc.
Note: direction 1 belongs to the palliative, but the surface is fast; direction 2, 3 can actually speed up the boot speed.
Then we'll actually apply it in the project.
Third, start the theme of acceleration switch
Follow the official documentation: Use the activity's Windowbackground theme property to provide a simple drawable for the activated activity.
Layout XML File:
Resource file configuration manifest file:
In the manifest file
In activity
So at the start, will show an interface, this interface is the style set in manifest, and so after the activity loaded, then to load the activity interface, and in the activity interface, we set the theme back to normal theme, Thus producing a quick sensation. However, as the previous summary of this approach does not really accelerate the start-up process, but through the interactive experience to optimize the performance of the display.
Note: Also from the official document "Launch-time performance".
Iv. launch the accelerated avoid Heavy App initialization
Through the code analysis we can get the app-initiated business workflow flowchart:
App Cold start business workflow flowchart
In this chapter we focus on the initialization part: in the application and first screen activity we mainly do:
- The initialization of Multidex and Tinker is performed first, and the optimization of Multidex is not described in this article, referring to my previous Multidex series of articles.
- In the application, the initialization of various tripartite components is mainly done.
All three-party components in the project, in addition to listening to the cloud, are preemptive, initialized in the application main thread. This type of initialization must be too heavy:
- Consider the asynchronous initialization of three-party components, without blocking the main thread;
- Delay the initialization of some of the three-party components; in fact, we coarse-grained all three-party components into the asynchronous task, may appear in the Workthread has not been initialized but the mainthread has been used in the error, so this situation is recommended to delay before the initialization of use;
- And how to open Workthread also have the attention, this topic in detail below.
Project modification:
- The Allies, bugly, listening clouds, Growingio, blockcanary and other components are placed in the Workthread initialization;
- Delay map positioning, imageloader, own statistics and other components initialization: map and its own statistics delay of 4 seconds, when the application has been opened, and Imageloader
Since the invocation relationship cannot be asynchronous and the delay is too long, the initialization is deferred from application to splashactivity, and Eventbus must be initialized in application because it is used in the activity.
Three-party Component invocation optimization sample code
Note: The 2-second stop on the splash screen can be used to delay the time-consuming operation to this interval.
V. Diagnosing the problem to start accelerating
In this section we are actually locating time-consuming operations, which we typically use blockcanary or Anrwatchdog to find time-consuming operations in the development phase, but are not able to 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.
Launch the app, click on the Start Method tracing, click again after the app launches, will automatically open the. trace file that was recorded by the operation, it is recommended to use the DDMS to view, more convenient and comprehensive features.
Apply startup trace file analysis diagram before optimization
The left side is the specific thread that occurs, the right side is the timeline that occurs, and the following is the specific method information that occurs. Note Two columns: Real Time/call (actual occurrence time), calls+recurcalls/total (number of occurrences);
We can get the following information:
- You can visually see that the Mainthread has a long timeline, indicating that most tasks are performed in Mainthread;
- It is really time-consuming to see some of the code in the program by real Time/call descending order;
- On the next page you can see that some of the three-party SDK is also time-consuming;
Even with time-consuming operations, there is no problem if it happens correctly in Workthread. So we need to confirm the threads that these methods execute and the timing of the occurrences. These operations, if they occur in the main thread, may not be the condition of the ANR, but the lag is inevitable! Combined with the previous chapter diagram of the app cold start business Operation flowchart and analysis diagram, again look at the code we can see: some time-consuming operations such as IO reads do occur in the main thread. In fact, in the TraceView, clicking on the name of the execution function can not only track how time is spent on the parent and subclass, but also in the method execution timeline to see exactly which thread and time-consuming interface flashes.
Analysis to a part of the time-consuming operation occurs in the main thread, then we have to change the time-consuming operation to sub-thread is not all right? Not also!!
- The lag cannot all be solved by async, the wrong use of engineering thread not only can not improve the lag, but may aggravate the lag. Whether the need to open the work thread needs to be based on specific performance bottleneck root-specific analysis, the appropriate remedy, not generalize;
- And how to open the thread is also learned: Thread, Threadpoolexecutor, Asynctask, Handlerthread, Intentservice, etc. all have pros and cons For example, threadpoolexecutor is typically more efficient and advantageous than thread, but the performance of a single point in a given scenario is better than Threadpoolexecutor: The same object is created, The cost of threadpoolexecutor is significantly larger than that of thread;
- The correct thread-opening is not a panacea, such as executing a network request creates a thread pool, and the correct creation of a thread pool in application is bound to slow down the boot, so a deferred operation is also necessary.
With detailed tracking of the TraceView and detailed comparison of the code, I found that the lag occurred in:
- Part of the database and IO operations occur in the first screen activity main thread;
- A thread pool is created in application;
- The first screen activity network request dense;
- The use of worker threads is not set to priority;
- The information is not cached and the same information is obtained repeatedly;
- Process issues: For example, every time a splash screen is downloaded, when used;
and other detail questions:
- Execute useless old code;
- Execute the code used in the development phase;
- Perform repetitive logic;
- Call the extra code in the three-party SDK or demo;
Project modification:
1. Both the database and IO operations are moved to the worker thread, and the thread priority is set to Thread_priority_background, so that the working thread can get up to 10% of the time slices, giving priority to the main thread execution.
2. Process carding, postpone execution;
In fact, this step is most effective for project initiation acceleration. Through the process of carding to find part of the process call timing premature, error, such as:
- Updates and other operations do not have to be called on the first screen, resulting in resource competition;
- Call the iOS in order to circumvent audit switch, resulting in a dense network request;
- Own statistics in the application call to create a fixed number of 5 thread pool, resulting in resource competition, in the TraceView function diagram, the last line can see the number 12 execution 5 times, time-consuming ranking forefront; The creation of the thread pool is necessary but can be deferred.
- Modify the ad splash screen logic to take effect next time.
3. Other optimizations;
- Remove the old code that is useless but executed;
- Remove code that is used in the development phase but is executed online;
- Eliminate repetitive logic execution code;
- Remove redundant code from calling the three-party SDK or demo;
- Information cache, the common information is only obtained in the first time, and then taken from the cache;
- The project is a multi-process architecture that executes application OnCreate () only in the main process;
Business code Optimization Example
Through the above three steps and the optimization of three-party components: application and the first screen activity callback during the main thread there is no time-consuming, scramble for resources and so on. In addition to the layout optimization, memory optimization, and other parts of the technology, because the application of cold start is not a bottleneck point, here do not expand the details, according to actual projects can be processed.
Six, the contrast effect:
Statistical application startup time via ADB command: ADB shell am start-w first screen activity.
Using MX3 and nexus6p under the same conditions, starting 5 times, comparing the pre-optimization with the optimized start-up time;
Before optimization:
MX3
Thistime |
TotalTime |
WaitTime |
1237 |
2205 |
2214 |
1280 |
2181 |
2189 |
1622 |
2508 |
2513 |
1485 |
2434 |
2443 |
1442 |
2418 |
2429 |
nexus6p
Thistime |
TotalTime |
WaitTime |
1229 |
1832 |
1868 |
1268 |
1849 |
1880 |
1184 |
1780 |
1812 |
1262 |
1845 |
1876 |
1164 |
1766 |
1807 |
After optimization:
MX3
Thistime |
TotalTime |
WaitTime |
865 |
1516 |
1523 |
911 |
1565 |
1573 |
812 |
1406 |
1418 |
962 |
1564 |
1574 |
925 |
1566 |
1577 |
nexus6p
Thistime |
TotalTime |
WaitTime |
603 |
1192 |
1243 |
614 |
1076 |
1115 |
650 |
1120 |
1163 |
642 |
1107 |
1139 |
624 |
1084 |
1124 |
Contrast:
MX3 Lifting 35%
|
thistime | average
totaltime | average
waittime | average
Before optimization |
1413 |
2349 |
2357 |
After optimization |
895 |
1523 |
1533 |
nexus6p Lifting 39%
|
thistime | average
totaltime | average
waittime | average
Before optimization |
1221 |
1814 |
1848 |
After optimization |
626 |
1115 |
1156 |
- Command meaning:
Thistime: The start time of the last activity started;
TotalTime: The start time of all your activity;
Waittime:activitymanagerservice the total time to start the app activity (including the current activity's onpause () and your activity's startup).
Vii. questions:
1, still can continue to optimize the direction?
- Project using retrofit network Request library, Fastconverterfactory do JSON parser, TraceView see fastconverterfactory in the creation process is also relatively time-consuming, Consider changing it to gsonconverterfactory. But because the inheritance relation of the class cannot be replaced in a short time, it is left as the optimization point.
- It is possible to consider merging some interfaces into one at startup, reducing the number of network requests and decreasing the frequency according to the actual situation.
- The components of the same function are reserved only one, for example: Friends, Growingio, own statistics and other functions of repetition;
- Use Redex to optimize; the experiment Redex found that the APK volume is really a little bit smaller, but the boot speed has not changed and may need to be studied.
2, asynchronous, delay initialization and operation of the basis?
Note that not every component's initialization and operation can be asynchronous or deferred, depending on the component's invocation relationship and the needs of its own project-specific business. Ensure that you can asynchronously asynchronously, and not asynchronously, as late as possible. Let the app start and then operate.
3, the general application to start the accelerated routine?
- Use the theme to quickly display the interface;
- Asynchronous initialization of components;
- Combing business logic, delaying initialization of components and operations;
- Use threads correctly;
- Remove useless code, repeat logic, and so on.
4. Other
- Speed up the start up by 35% does not mean that the previous code is a problem, from a business perspective, the code is not wrong, the business requirements are realized. But in this stage of speed at startup, ignoring details can lead to performance bottlenecks.
- During the development process, the core module and application phase such as starting, using TraceView analysis, early detection of bottlenecks.
Reference article: "Official document--launch-time Performance"
Welcome to the public number: Regularly share Java, Android Dry!
Android performance Optimization (i) Start acceleration 35%