Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 安卓(Android)開發之統計App啟動時間

安卓(Android)開發之統計App啟動時間

編輯:關於Android編程

前言

作為 Android 開發者,想必多多少少要接觸啟動速度優化相關的事情,當用戶越來越多,產品的功能也隨著迭代越來越多,App 逐漸變得臃腫是一件很常見的現象,甚至可以說是不可避免的現象,隨之而來的工作就是優化 App 性能,其中最主要的一項就是啟動速度優化。但本文的主角並不是啟動速度優化,而是啟動時間統計。

一、啟動類型

工欲善其事,必先利其器。想要優化 App 的啟動速度,必須有准確衡量啟動時間的方法,否則優化完之後效果怎樣,自己都不知道,說出去別人也不信服不是。在做 App 啟動時間統計之前,當然必須弄明白有哪些啟動類型,每種啟動類型的特點。通常來說,在安卓中應用的啟動方式分為以下幾種:

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

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

3、首次啟動:首次啟動嚴格來說也是冷啟動,之所以把首次啟動單獨列出來,一般來說,首次啟動時間會比非首次啟動要久,首次啟動會做一些系統初始化工作,如緩存目錄的生產,數據庫的建立,SharedPreference的初始化,如果存在多 dex 和插件的情況下,首次啟動會有一些特殊需要處理的邏輯,而且對啟動速度有很大的影響,所以首次啟動的速度非常重要,畢竟影響用戶對 App 的第一映像。

二、本地啟動時間的統計方式

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

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 即可,這個時間才是自己應用真正啟動的耗時。

三、線上啟動時間的統計方式

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

應用的主要啟動流程

關於 App 啟動流程的文章很多,文章底部有一些啟動流程相關的參考文章,這裡只列出大致流程如下:

    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 的實例,並執行它的生命周期函數。

總結過程就是:用戶在 Launcher 程序裡點擊應用圖標時,會通知 ActivityManagerService 啟動應用的入口 ActivityActivityManagerService 發現這個應用還未啟動,則會通知 Zygote 進程孵化出應用進程,然後在這個應用進程裡執行 ActivityThread main 方法。應用進程接下來通知 ActivityManagerService 應用進程已啟動,ActivityManagerService 保存應用進程的一個代理對象,這樣 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 的啟動時間,那麼至少要記錄兩個點,一個起始時間點,一個結束時間點。

起始時間點

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

結束時間點

結束時間點理論上要選在 App 顯示出第一屏界面的時候,但是在什麼位置 App 顯示出第一屏界面呢?網上很多文章說在 Activity onResume 方法執行完成之後,Activity 就對用戶可見了,實際上並不是,一個 Activity 走完onCreate onStart onResume 這幾個生命周期之後,只是完成了應用自身的一些配置,比如 Activity 主題設置 window 屬性的設置 View 樹的建立,但是其實後面還需要各個 View 執行 measure layout draw等。所以在 OnResume 中記錄結束時間點的 Log 並不准確,大家可以注意一下上面流程中最後一個函數 Activity.onWindowFocusChanged,下面是它的注釋:

/**
*Called when the current {@link Window} of the activity gains or loses
* focus. This is the best indicator of whether this activity is visible
* to the user. The default implementation clears the key tracking
* state, so should always be called.
...
*/

通過注釋我們可以看到,這個函數是判斷 activity 是否可見的最佳位置,所以我們可以在 Activity.onWindowFocusChanged 記錄應用啟動的結束時間點,不過需要注意的是該函數,在 Activity 焦點發生變化時就會觸發,所以要做好判斷,去掉不需要的情況。

總結

以上就是關於安卓(Android)開發之統計App啟動時間的全部內容,本文的內容小編覺得還是很重要的,還是那句話:工欲善其事,必先利其器,准備工作做的充分,做事自然有理有據。希望本文的內容對大家有所幫助。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved