您好,登錄后才能下訂單哦!
前言
隨著App的開發到了某個階段必然會遇到一個需求,那就是優化頁面的啟動時間。
第一個問題:有什么方法可以去統計頁面的啟動時間呢?
adb?logcat?-s?ActivityManager?|?grep?"Displayed"
上面的命令行可用來進行查看。
第二個問題:啟動時間是包括了哪些流程,是如何被計算出來的呢?
App啟動主要經過如下幾個流程
Launch the process.
Initialize the objects.
Create and initialize the activity.
Inflate the layout.
Draw your application for the first time.
最末尾的步驟5是繪制你的界面。所以完整的啟動時間是要到繪制完成為止。
那么繪制界面對應的是什么時候呢?一般我們開發,最晚能被回調的是在onResume方法,那么onResume方法是在繪制之后還是之前呢?
no code no truth
?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);
看上面的代碼,就先放結論了。
在performResumeActivity 中進行了onResume的回調,在wm.addView 中進行了繪制,因此onResume的方法是在繪制之前,在onResume中做一些耗時操作都會影響啟動時間。
下面就剝一下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中,由于有LoadingView時間,我把Adapter的綁定也挪出去了。看下優化前后效果圖 ,效果還是挺明顯的;
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。