Trigger app launch optimization best practices
This article in Diycode and CSDN personal blog at the same time, focus on the author's Diycode account or the author Weibo can be the first time to receive a new article push.
Many of the graphs in this article are in the sixth quarter of the Google Performance Tuning guide
Google gives an optimization guide to the Town building
Https://developer.android.com/topic/performance/launch-time.html
splash screen Definition
Android's official performance optimization paradigm, starting in the sixth quarter, launched a series of optimization practices for app launch, with the following addresses:
Https://www.youtube.com/watch?v=Vw1G1s73DsY&index=74&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE
It is conceivable that the launch performance of the app is very important. At the same time, Google also gives a very detailed design definition for the app splash screen, as shown below.
Https://material.google.com/patterns/launch-screens.html
In fact, the first time, splash screen is used when the app is not fully launched, so that users do not confuse the app to start and join a design. And now a lot of apps, basically the splash screen as an advertisement, propaganda page, seemingly have lost the original meaning, but splash screen, anyway, in an app launch time, are very important, design things, to UE bar, development to do, is to let the app launch experience, do the best.
App Launch process
The entire process of app startup can be broken down into the following processes:
- Users click on the app Icon on launcher
- The system creates a process for the app, showing the startup window
- The app creates its own components in the process
This process can be described in the following picture:
And we can optimize, that is, the creation of the following application, the system's process allocation and some of the window switch animation effect, are related to ROM, we can not handle. So, we need to focus on the application creation process.
The above is an official note, and we will explain it in a more popular language.
When the user clicks on the desktop icon, the system is ready, to the app to allocate process space, as if to the hotel open room, but you can not directly into the room, you have to take the elevator to the room, then you take the elevator this time, is actually the system preparation time, then the system of the preparation time is generally not too long, But if the opening is a presidential suite, the system will have to spend a lot of time to take care of, so the system to all users have prepared a transition interface, this interface, is the start of the black screen \ White screen, that is, you take the elevator inside to see the small ads, after watching the ads, you went to the room, and then you want to do The speed of what to do, depends entirely on the speed at which you open the door, you open fast, natural that what fast, so here is the developer can optimize the place, some developers take a key for several seconds, and some only hundreds of milliseconds, completely affect the efficiency behind that.
So generally speaking, the story to this end, but, the system, that is, this hotel, is not a pheasant hotel, he also want to do as much as possible to let customer satisfaction, so that there will be repeat customers ah, so, the hotel has done an optimization, you can let each customer define in the elevator when you want to see what! That is, the system in the loading of the app, the first is to load the resource file, which includes the activity to start the theme, and this theme, is can be customized, that is, customers in the elevator to want to see things, rather than the same white screen or black screen, He can customize a lot of things, such as actionbar, backgrounds, Statbar and so on.
Measurement of startup time definition of activity start time
For activity, starting with OnCreate (), OnStart (), Onresume () These life cycle functions, but even if these lifecycle method callbacks end, the application is not fully started, but also need to wait until the view tree is all built, It is generally assumed that the view in the Setcontentview is all over and counted as the application is fully activated.
Display time
After API19, Android adds display log information to the system log, which can be found in the system by filtering the two keywords of activitymanager and display:
$ adb logcat | grep “ActivityManager”ActivityManager: Displayed com.example.launcher/.LauncherActivity: +999ms
Captured log:
The time, in fact, is the activity start, to the layout of the entire display process, but note that this does not include the loading of data, because many apps are loaded with lazy loading mode, that is, after the data is pulled, then refresh the default UI.
Reportfullydrawn
As I said earlier, the display time in the system log is just the timing of the layout and does not include the time spent on lazy loading of some data, so the system defines a similar "custom escalation Time"--reportfullydrawn.
It is also a picture of Google that uses a map to illustrate:
Reportfullydrawn is called by ourselves, and is usually called manually after all of the data has been loaded, thus adding a log to it:
$ adb logcat | grep “ActivityManager”ActivityManager: Displayed com.example.launcher/. LauncherActivity: +999msActivityManager: Fully drawn com.example.launcher/. LauncherActivity: +1s999ms
In general, the scenario used is as follows:
public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Void> { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public void onLoadFinished(Loader<Void> loader, Void data) { // 加载数据 // …… // 上报reportFullyDrawn reportFullyDrawn(); } @Override public Loader<Void> onCreateLoader(int id, Bundle args) { return null; } @Override public void onLoaderReset(Loader<Void> loader) { }}
Note, however, that this approach requires api19+, so the SDK version needs to be judged.
Calculate Start Time--adb
The ADB command allows you to count the start-up time of your application, as follows:
? ~ adb shell am start -W com.xys.preferencetest/.MainActivityStarting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.xys.preferencetest/.MainActivity }Status: okActivity: com.xys.preferencetest/.MainActivityThisTime: 1047TotalTime: 1047WaitTime: 1059Complete
The directive gives a total of three time:
- Thistime: The start time of the last activity started
- TotalTime: The start time of all your activity
- Waittime:activitymanagerservice total time to start the app activity (including the current activity's onpause () and your activity's startup)
These three times are not very well understood and we can break the whole process down
1. OnPause ()--2 of the previous activity. The system calls AMS time-consuming--3. The first activity (perhaps a splash screen) starts time-consuming--4. The first activity OnPause () takes time--5. The second activity starts time-consuming
Then, Thistime represents 5 (the last activity start time). TotalTime represents a total time-consuming 3.4.5 (if there is only one activity at startup, then Thistime and totaltime should be the same). Waittime indicates that all operations are time-consuming, that is, 1.2.3.4.5 all time-consuming.
Each time it is given may not be the same, and the application starts from the first installation to the back each time it starts normally, it will be different depending on whether the system is allocating process space.
Calculate Start time--screen Record
The analysis of start-up through the recording screen is a good way to provide us with a more convenient and accurate way in api21+,android:
? ~ adb shell screenrecord --bugreport /sdcard/test.mp4
Android in Screenrecord a new parameter--bugreport, then add this parameter, the recorded video, in the upper left corner will increase the display of a line of numbers.
Before the video starts, the device information and some parameters are displayed:
After the video starts, there will be a row of numbers in the upper left corner:
Example: 15:31:22.261 f=171 (0)
Among them, the previous 4 numbers, is the timestamp, that is, 15 points 31 minutes 22 seconds 261,f= After the number is the current frame number, note, not the frame rate, but represents the current is the first few frames, the number in parentheses, representing the "Dropped frames
Count ", which is the number of dropped frames.
With this thing, you can see this information very clearly in combination with the video.
Start-up time debug analog start delay
During testing, we can perform a delayed simulation of the startup in the following way:
SystemClock.sleep(2000)
or directly through:
try { Thread.sleep(2000);} catch (InterruptedException e) { e.printStackTrace();}
or by:
new Handler().postDelayed(new Runnable() { @Override public void run() { // Delay }}, 2000);
These scenarios can be simulated for start-up delays.
Forced cold start
Set to No Background in Background Process limit in developer options Processes
Optimize point static Block
Many of the static blocks in the code are doing some initialization work, especially in the ContentProvider initialization of some urimatcher in the static block, which can be made into lazy loading mode.
Application
Application is the main entrance of the program, especially many third-party SDK will need to do a lot of initialization in application OnCreate, have to say, a variety of third-party SDK, are particularly fond of this "battleground", coupled with some of their own library initialization, Will overwhelm the entire application.
The method of optimization is nothing more than the following:
- Deferred initialization
- Background tasks
- Interface Pre-loading
Blocking
There are many cases of blocking, such as disk IO blocking (read and write files, sharedperfences), network blocking (which should not be done now), and high CPU usage (decryption, rendering, parsing, and so on).
View level
See the "Android Heroes biography"
Time-consuming method
By using the TraceView && systrace && Method Tracing tool to troubleshoot, see "Android Elite Biography: The weapon of divine soldiers"
The general process of app startup optimization
- Analyze time-consuming methods and components through TraceView, Systrace.
- Comb each library, component that starts loading.
- The library will be combed out, according to the functions and requirements of the division, design the start time of the library.
- and interactive communication, design start screen, according to the previous method to optimize.
Solution Theme
When the system loads an activity, onCreate () is a time-consuming process, so in this process the system will actually draw some initial interface, similar to placeholder, in order for the user to have a better experience.
The system will first read the current activity's theme and then draw according to the configuration in the theme, and when the activity is loaded, it will be replaced with a real interface. As a result, Google's solution is to use the Android:windowbackground property to configure the pre-load configuration, and not only to configure the color, but also to configure the image, for example, We can use a layer-list as the Android:windowbackground to display the graph:
Start_window.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque"> <item android:drawable="@android:color/darker_gray"/> <item> <bitmap android:gravity="center" android:src="@mipmap/ic_launcher"/> </item></layer-list>
As you can see, the overlay of the images is achieved through layer-list, allowing developers to freely assemble.
The android:opacity= "opaque" parameter in the configuration is designed to prevent background flicker from appearing at startup.
You can then set a new style, which is the style that the activity preloaded.
<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> </style> <style name="StartStyle" parent="AppTheme"> <item name="android:windowBackground">@drawable/start_window</item> </style></resources>
OK, specify the style that needs to be preloaded in the activity below in Mainifest:
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.xys.startperformancedemo"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity" android:theme="@style/StartStyle"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application></manifest>
Note here that it must be the activity's theme, not the application theme.
Finally, before the activity loads the real interface, it's good to set the theme back to the normal theme:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { setTheme(R.style.AppTheme); super.onCreate(savedInstanceState); SystemClock.sleep(2000); setContentView(R.layout.activity_main); }}
In this activity, I used Systemclock.sleep (2000) to simulate a time-consuming process for activity loading, before the Super.oncreate (savedinstancestate) Call, Sets the theme back to its original theme.
The effect of setting this way is as follows:
Start, will first show a screen, this screen is the system to parse the style, and so on after the activity loaded completely, will load the activity interface, and in the activity interface, we set the theme to normal theme, so as to achieve a friendly start-up experience , this approach does not really accelerate the start-up process, but through the interactive experience to optimize the performance of the display.
Asynchronous initialization
This is very simple, let the app in the OnCreate as much as possible to do things, and use the multi-core features of the phone, as much as possible use of multi-threading, such as some third-party framework initialization, if you can put the thread, as far as possible into the thread, the simplest, you can directly new thread (), of course, You can also perform asynchronous initialization work through a common line pool, which is the best way to compress the startup time
Deferred initialization
Deferred initialization does not reduce the startup time, but instead allows time-consuming operations to make way for the UI to draw, delaying time-consuming operations until the UI is loaded, so it is recommended that the Mdecoview.post method be used for lazy loading, with the following code:
getWindow().getDecorView().post(new Runnable() { @Override public void run() { …… }});
Our Contentview is added to the root layout through the Mdecoview.addview, so in this way, you can let the deferred loading content, after the initialization of the Contentview, and then execute, to ensure the smoothness of the UI drawing.
Intentservice
Intentservice is a class that inherits from the service and processes asynchronous requests, and within Intentservice, there is a worker thread that handles time-consuming operations, starting the Intentservice the same way as a traditional service, and When the task is finished, the intentservice automatically stops, without the need to manually control it.
public class InitIntentService extends IntentService { private static final String ACTION = "com.xys.startperformancedemo.action"; public InitIntentService() { super("InitIntentService"); } public static void start(Context context) { Intent intent = new Intent(context, InitIntentService.class); intent.setAction(ACTION); context.startService(intent); } @Override protected void onHandleIntent(Intent intent) { SystemClock.sleep(2000); Log.d(TAG, "onHandleIntent: "); }}
We will take the time-consuming task to Intentservice, the system will automatically open the thread to deal with, at the same time, at the end of the mission, but also to end their service, how human! OK, just start this intentservice in the application or activity OnCreate:
@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); InitIntentService.start(this);}
Finally, don't forget to register your service at mainifest.
Using Activitylifecyclecallbacks
This approach provided by the framework can monitor the life cycle of all activity, where we can put some UI-related initialization operations here by onactivitycreated such a callback, and Avoid repetitive initialization by unregisteractivitylifecyclecallbacks. At the same time, here onactivitycreated callback parameter bundle, can be used to distinguish whether the system is collected by the activity.
public class MainApplication extends application {@Override public void onCreate () {super.oncreate (); Initialize basic content//... registeractivitylifecyclecallbacks (new Activitylifecyclecallbacks () {@Overri De public void onactivitycreated (activity activity, Bundle savedinstancestate) {Unregisteractiv Itylifecyclecallbacks (this); Initialize UI-related content//...} @Override public void onactivitystarted (activity activity) {} @Override Publi c void onactivityresumed (activity activity) {} @Override public void onactivitypaused (Ac Tivity activity) {} @Override public void onactivitystopped (activity activity) { } @Override public void onactivitysaveinstancestate (activity activity, Bundle outstate) { } @Override Public void onactivitydestroyed (activity activity) {}}); }}
Resource optimization
There are several aspects, one is the optimization of layout, layout level, one is to optimize resources, as far as possible to streamline resources, avoid garbage resources, which can be achieved by confusing and tinypng these tools.
Pot Toss Solution
Here are two different scenarios that are configured in the style:
<item name="android:windowDisablePreview">true</item>
And
<item name="android:windowIsTranslucent">true</item><item name="android:windowNoTitle">true</item>
Let's start by looking at the effect of doing this:
The setting effect is similar, that is, by canceling, transparent system of the unified loading page to achieve the start of "acceleration", in fact, is a "shake the pot" process. It is strongly recommended that developers do not do "so-called start-up acceleration" in this way, although it seems that their app starts very quickly and is completed in an instant, but actually hides the actual boot interface.
System said: This pot, we do not back!
No solution
Corresponding to 5.0 of the 65535 problems, at present can only be processed through the multidex, and on the machine under 5.0, the system before the loading of the merge Dex process, it may be very long, this is a temporary solution, can only hope that the latter Multidex optimization.
Ok,app start optimization as above, its key process, still is the analysis of time-consuming operation, and how to design a reasonable start sequence, I hope you can be introduced in the way to the application of the launch optimization.
Reprint Please specify: Android Development Chinese station? Trigger app launch optimization best practices
Trigger app launch optimization best practices