Android 統計啓動時長

1,啓動類型

1>.冷啓動:當啓動應用時,後臺沒有該應用的進程,這時系統會重新創建一個新的進程分配給該應用,這個啓動方式就是冷啓動。冷啓動因爲系統會重新創建一個新的進程分配給它,所以會先創建和初始化 Application 類,再創建和初始化 MainActivity 類,最後顯示在界面上。

2>.熱啓動:當啓動應用時,後臺已有該應用的進程(例:按back鍵、home鍵,應用雖然會退出,但是該應用的進程是依然會保留在後臺,可進入任務列表查看),所以在已有進程的情況下,這種啓動會從已有的進程中來啓動應用,這個方式叫熱啓動。熱啓動因爲會從已有的進程中來啓動,所以熱啓動就不會走 Application 這步了,而是直接走 MainActivity,所以熱啓動的過程不必創建和初始化 Application,因爲一個應用從新進程的創建到進程的銷燬,Application 只會初始化一次。

2,本地啓動時間的統計方式

如果是本地調試的話,統計啓動時間還是很簡單的,通過命令行方式即可:

adb shell am start -w packagename/activity

輸出的結果:

$ adb shell am start -W com.speed.test/com.speed.test.HomeActivity
 
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.speed.test/.HomeActivity }
 
Status: ok
 
Activity: com.speed.test/.HomeActivity
 
ThisTime: 496
 
TotalTime: 496
 
WaitTime: 503
 
Complete

WaitTime 返回從 startActivity 到應用第一幀完全顯示這段時間. 就是總的耗時,包括前一個應用 Activity pause 的時間和新應用啓動的時間;

ThisTime 表示一連串啓動 Activity 的最後一個 Activity 的啓動耗時;

TotalTime 表示新應用啓動的耗時,包括新進程的啓動和 Activity 的啓動,但不包括前一個應用Activity pause的耗時。

開發者一般只要關心 TotalTime 即可,這個時間纔是自己應用真正啓動的耗時。

3,線上啓動時間的統計方式

當 App 發到線上之後,想要統計 App 在用戶手機上的啓動速度,就不能通過命令行的方式進行統計了,基本上都是通過打 Log 的方式將啓動時間發送上來。那麼在什麼位置加啓動時間統計的 Log 就尤爲重要,Log 添加的位置直接決定啓動時間統計的是否準確,同樣也會影響啓動速度優化效果的判斷。要想找到合適準確的位置記錄啓動時間的 Log,就需要了解應用的啓動流程,和各個生命週期函數的調用順序。下面來分析下到底在什麼位置打 Log 記錄啓動時間比較合適。

應用的主要啓動流程

1>.通過 Launcher 啓動應用時,點擊應用圖標後,Launcher 調用 startActivity 啓動應用。

2>.Launcher Activity 最終調用 Instrumentation 的 execStartActivity 來啓動應用。

3>.Instrumentation 調用 ActivityManagerProxy (ActivityManagerService 在應用進程的一個代理對象) 對象的 startActivity 方法啓動 Activity。

4>.到目前爲止所有過程都在 Launcher 進程裏面執行,接下來 ActivityManagerProxy 對象跨進程調用 ActivityManagerService (運行在 system_server 進程)的 startActivity 方法啓動應用。

5>.ActivityManagerService 的 startActivity 方法經過一系列調用,最後調用zygoteSendArgsAndGetResult 通過 socket 發送給 zygote 進程,zygote 進程會孵化出新的應用進程。

6>.zygote 進程孵化出新的應用進程後,會執行 ActivityThread 類的 main 方法。在該方法裏會先準備好 Looper 和消息隊列,然後調用 attach 方法將應用進程綁定到 ActivityManagerService,然後進入 loop 循環,不斷地讀取消息隊列裏的消息,並分發消息。

7>.ActivityManagerService 保存應用進程的一個代理對象,然後 ActivityManagerService 通過代理對象通知應用進程創建入口 Activity 的實例,並執行它的生命週期函數。

生命週期函數執行流程

上面的啓動流程是 Android 提供的機制,作爲開發者我們需要清楚或者至少了解其中的過程和原理,但我們並不能在這過程中做什麼文章,我們能做的恰恰是從上述過程中最後一步開始,即ActivityManagerService 通過代理對象通知應用進程創建入口 Activity 的實例,並執行它的生命週期函數開始,我們的啓動時間統計以及啓動速度優化也是從這裏開始。下面是 Main Activity 的啓動流程:

-> Application 構造函數

-> Application.attachBaseContext()

-> Application.onCreate()

-> Activity 構造函數

-> Activity.setTheme()

-> Activity.onCreate()

-> Activity.onStart

-> Activity.onResume

-> Activity.onAttachedToWindow

-> Activity.onWindowFocusChanged

如果打 Log 記錄 App 的啓動時間,那麼至少要記錄兩個點,一個起始時間點,一個結束時間點。

1.起始時間點

起始時間點比較容易記錄:

1>.如果記錄冷啓動啓動時間一般可以在 Application.attachBaseContext() 開始的位置記錄起始時間點,因爲在這之前 Context 還沒有初始化,一般也幹不了什麼事情,當然這個是要視具體情況來定,其實只要保證在 App 的具體業務邏輯開始執行之前記錄起始時間點即可。

2>.如果記錄熱啓動啓動時間點可以在 Activity.onRestart() 中記錄起始時間點。

2.結束時間點

1>.不應該在onResume方法執行完成後記錄:Activity 的 onResume 方法執行完成之後,Activity 就對用戶可見了,實際上並不是,一個 Activity 走完onCreate onStart onResume 這幾個生命週期之後,只是完成了應用自身的一些配置,比如 Activity 主題設置 window 屬性的設置 View 樹的建立,但是其實後面還需要各個 View 執行 measure layout draw等。所以在 OnResume 中記錄結束時間點的 Log 並不準確

2>.我們可以在 Activity.onWindowFocusChanged 記錄應用啓動的結束時間點,不過需要注意的是該函數,在Activity 焦點發生變化時就會觸發,所以要做好判斷,去掉不需要的情況。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章