IdleHandler,頁面啓動優化神器

隨着App的開發到了某個階段必然會遇到一個需求,那就是優化頁面的啓動時間。html

第一個問題:有什麼方法能夠去統計頁面的啓動時間呢?android

adb logcat -s ActivityManager | grep "Displayed"

複製代碼

上面的命令行可用來進行查看。bash

第二個問題:啓動時間是包括了哪些流程,是如何被計算出來的呢?app

App啓動主要通過以下幾個流程ide

  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.

最末尾的步驟5是繪製你的界面。因此完整的啓動時間是要到繪製完成爲止。oop

那麼繪製界面對應的是何時呢?通常咱們開發,最晚能被回調的是在onResume方法,那麼onResume方法是在繪製以後仍是以前呢?優化

no code no truthui

final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
            //省略部分代碼
            r = performResumeActivity(token, clearHide, reason);
            //省略部分代碼
            if (a.mVisibleFromClient) {
                    if (!a.mWindowAdded) {
                        a.mWindowAdded = true;
                        wm.addView(decor, l);
                 
複製代碼

看上面的代碼,就先放結論了。this

在performResumeActivity 中進行了onResume的回調,在wm.addView 中進行了繪製,所以onResume的方法是在繪製以前,在onResume中作一些耗時操做都會影響啓動時間。spa

下面就剝一下onResume的邏輯,繪製的有興趣能夠本身看源碼。 首先performResumeActivity中會調用r.activity.performResume();

public final ActivityClientRecord performResumeActivity(IBinder token,
            boolean clearHide, String reason) {
          //省略部分代碼
        
            try {
                r.activity.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();

               //省略部分代碼
               }
               }
複製代碼

而後在performResume中調用了 mInstrumentation.callActivityOnResume(this);

final void performResume() {
       //省略部分代碼
        mInstrumentation.callActivityOnResume(this);
        //省略部分代碼
    }
複製代碼

最後在callActivityOnResume 調用了onResume

public void callActivityOnResume(Activity activity) {
        activity.mResumed = true;
        activity.onResume();
        //省略代碼
    }
複製代碼

到了此處就算真正調用到了onResume的方法。

既然知道了onResume中作的操做會影響到啓動時間,那麼就有一個優化啓動時間的思路了。

思路

把在onResume以及其以前的調用的但非必須的事件(如某些界面View的繪製)挪出來找一個時機(即繪製完成之後)去調用。那樣啓動時間天然就縮短了。可是總體作的事並無明顯變化。那麼這個時機是什麼呢?

IdleHandler

看下IdleHandler的源碼

/**
     * 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();
    }
複製代碼

從這個源碼可知道,IdleHandler即在looper裏面的message處理完了的時候去調用,這不就是咱們onResume調用完了之後的時機麼。

來一張圖說明一下,明顯的IdleHandler在onResume以及performTraversals繪製以後調用 idlehandler

由這個思路我把本身負責的頁面中的一些界面的繪製邏輯挪到了IdleHandler中,因爲有LoadingView時間,我把Adapter的綁定也挪出去了。看下優化先後效果圖 defaultdefault效果仍是挺明顯的。

參考資料

相關文章
相關標籤/搜索