At a certain stage of App development, there will inevitably be a need to optimize the page launch time.

First question: Is there a way to count the startup time of a page?

adb logcat -s ActivityManager | grep "Displayed"

Copy the code

The command line above is available for viewing.

Second question: what processes are involved in startup time and how is it calculated?

App startup mainly goes through the following processes

  1. Launch the process.
  2. Initialize the objects.
  3. Create and initialize the activity.
  4. Inflate the layout.
  5. Draw your application for the first time.

The last step, step 5, is to draw your interface. So the full startup time is until the drawing is complete.

So when does drawing an interface correspond to? Usually the last thing we develop that can be called back is onResume method, so is onResume method after drawing or before drawing?

no code no truth

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {// omit some code r = performResumeActivity(token, clearHide, reason); // Omit some codeif (a.mVisibleFromClient) {
                    if(! a.mWindowAdded) { a.mWindowAdded =true;
                        wm.addView(decor, l);
                 
Copy the code

Look at the code above, put the conclusion first.

The onResume callback is performed in the performResumeActivity and is drawn in wm.addView, so the onResume method is to do time-consuming operations in the onResume before drawing that will affect the startup time.

Below strip onResume logic, draw interested can see their own source code. First, r.activity. PerformResume () is called in performResumeActivity;

public final ActivityClientRecord performResumeActivity(IBinder token, boolean clearHide, String "reason) {/ / omit part of the code try {state Richard armitage ctivity. OnStateNotSaved (); r.activity.mFragments.noteStateNotSaved(); checkAndBlockForNetworkAccess();if(r.pendingIntents ! = null) { deliverNewIntents(r, r.pendingIntents); r.pendingIntents = null; }if(r.pendingResults ! = null) { deliverResults(r, r.pendingResults); r.pendingResults = null; } r.activity.performResume(); // omit some code}}Copy the code

Then call in performResume mInstrumentation. CallActivityOnResume (this);

 final void performResume() {/ / omit part of the code mInstrumentation. CallActivityOnResume (this); // omit some code}Copy the code

Finally onResume is called in callActivityOnResume

 public void callActivityOnResume(Activity activity) {
        activity.mResumed = true; activity.onResume(); // omit code}Copy the code

At this point, the onResume method is actually called.

Now that you know that what you do in onResume affects the startup time, there is an idea to optimize the startup time.

Train of thought

Remove unnecessary events that are called before and before onResume (such as drawing certain interface views) and find a time to call them (after drawing). That should shorten the startup time. But there was no significant change in what they did overall. So what is the timing?

IdleHandler

Take a look at the IdleHandler source code

   /**
     * Callback interface for discovering when a thread is going to block
     * waiting for more messages.
     */
    public static interface IdleHandler {
        /**
         * Called when the message queue has run out of messages and will now
         * wait for more.  Return true to keep your idle handler active, false
         * to have it removed.  This may be called if there are still messages
         * pending in the queue, but they are all scheduled to be dispatched
         * after the current time.
         */
        boolean queueIdle();
    }
Copy the code

IdleHandler is called when the looper message is finished processing, which is when onResume is finished.

To illustrate, the obvious IdleHandler is called after onResume and performTraversals have been drawn

With this in mind, I moved some of the interface drawing logic in my page to IdleHandler. Due to LoadingView time, I also moved the Adapter binding out. Take a look at the before and after optimizationThe effect is quite obvious.

The resources

  • Developer.android.com/topic/perfo…
  • Wetest.qq.com/lab/view/35…