欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

安卓(Android)開發(fā)之統(tǒng)計App啟動時間

 更新時間:2016年08月10日 17:49:27   作者:單刀土豆  
當(dāng)大家要改善APP啟動速度優(yōu)化的時候,首先要知道App的啟動時間,那么改如何統(tǒng)計時間呢,下面我們一起來看看。

前言

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

一、啟動類型

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

1、冷啟動:當(dāng)啟動應(yīng)用時,后臺沒有該應(yīng)用的進(jìn)程,這時系統(tǒng)會重新創(chuàng)建一個新的進(jìn)程分配給該應(yīng)用,這個啟動方式就是冷啟動。冷啟動因為系統(tǒng)會重新創(chuàng)建一個新的進(jìn)程分配給它,所以會先創(chuàng)建和初始化 Application 類,再創(chuàng)建和初始化 MainActivity 類,最后顯示在界面上。

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

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

二、本地啟動時間的統(tǒng)計方式

如果是本地調(diào)試的話,統(tǒng)計啟動時間還是很簡單的,通過命令行方式即可:

adb shell am start -w packagename/activity

輸出的結(jié)果類似于:

$ 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 到應(yīng)用第一幀完全顯示這段時間. 就是總的耗時,包括前一個應(yīng)用 Activity pause 的時間和新應(yīng)用啟動的時間;

ThisTime 表示一連串啟動 Activity 的最后一個 Activity 的啟動耗時;

TotalTime 表示新應(yīng)用啟動的耗時,包括新進(jìn)程的啟動和 Activity 的啟動,但不包括前一個應(yīng)用Activity pause的耗時。

開發(fā)者一般只要關(guān)心 TotalTime 即可,這個時間才是自己應(yīng)用真正啟動的耗時。

三、線上啟動時間的統(tǒng)計方式

當(dāng) App 發(fā)到線上之后,想要統(tǒng)計 App 在用戶手機(jī)上的啟動速度,就不能通過命令行的方式進(jìn)行統(tǒng)計了,基本上都是通過打 Log 的方式將啟動時間發(fā)送上來。那么在什么位置加啟動時間統(tǒng)計的 Log 就尤為重要,Log 添加的位置直接決定啟動時間統(tǒng)計的是否準(zhǔn)確,同樣也會影響啟動速度優(yōu)化效果的判斷。要想找到合適準(zhǔn)確的位置記錄啟動時間的 Log,就需要了解應(yīng)用的啟動流程,和各個生命周期函數(shù)的調(diào)用順序。下面來分析下到底在什么位置打 Log 記錄啟動時間比較合適。

應(yīng)用的主要啟動流程

關(guān)于 App 啟動流程的文章很多,文章底部有一些啟動流程相關(guān)的參考文章,這里只列出大致流程如下:

    1、通過 Launcher 啟動應(yīng)用時,點擊應(yīng)用圖標(biāo)后,Launcher 調(diào)用 startActivity 啟動應(yīng)用。

    2、Launcher Activity 最終調(diào)用 Instrumentation execStartActivity 來啟動應(yīng)用。

    3、Instrumentation 調(diào)用 ActivityManagerProxy (ActivityManagerService 在應(yīng)用進(jìn)程的一個代理對象) 對象的 startActivity 方法啟動 Activity

    4、到目前為止所有過程都在 Launcher 進(jìn)程里面執(zhí)行,接下來 ActivityManagerProxy 對象跨進(jìn)程調(diào)用 ActivityManagerService (運行在 system_server 進(jìn)程)的 startActivity 方法啟動應(yīng)用。

    5、ActivityManagerService startActivity 方法經(jīng)過一系列調(diào)用,最后調(diào)用 zygoteSendArgsAndGetResult 通過 socket 發(fā)送給 zygote 進(jìn)程,zygote 進(jìn)程會孵化出新的應(yīng)用進(jìn)程。

    6、zygote 進(jìn)程孵化出新的應(yīng)用進(jìn)程后,會執(zhí)行 ActivityThread 類的 main 方法。在該方法里會先準(zhǔn)備好 Looper 和消息隊列,然后調(diào)用 attach 方法將應(yīng)用進(jìn)程綁定到 ActivityManagerService,然后進(jìn)入 loop 循環(huán),不斷地讀取消息隊列里的消息,并分發(fā)消息。

    7、ActivityManagerService 保存應(yīng)用進(jìn)程的一個代理對象,然后 ActivityManagerService 通過代理對象通知應(yīng)用進(jìn)程創(chuàng)建入口 Activity 的實例,并執(zhí)行它的生命周期函數(shù)。

總結(jié)過程就是:用戶在 Launcher 程序里點擊應(yīng)用圖標(biāo)時,會通知 ActivityManagerService 啟動應(yīng)用的入口 ActivityActivityManagerService 發(fā)現(xiàn)這個應(yīng)用還未啟動,則會通知 Zygote 進(jìn)程孵化出應(yīng)用進(jìn)程,然后在這個應(yīng)用進(jìn)程里執(zhí)行 ActivityThread main 方法。應(yīng)用進(jìn)程接下來通知 ActivityManagerService 應(yīng)用進(jìn)程已啟動,ActivityManagerService 保存應(yīng)用進(jìn)程的一個代理對象,這樣 ActivityManagerService 可以通過這個代理對象控制應(yīng)用進(jìn)程,然后 ActivityManagerService 通知應(yīng)用進(jìn)程創(chuàng)建入口 Activity 的實例,并執(zhí)行它的生命周期函數(shù)。

生命周期函數(shù)執(zhí)行流程

上面的啟動流程是 Android 提供的機(jī)制,作為開發(fā)者我們需要清楚或者至少了解其中的過程和原理,但我們并不能在這過程中做什么文章,我們能做的恰恰是從上述過程中最后一步開始,即 ActivityManagerService 通過代理對象通知應(yīng)用進(jìn)程創(chuàng)建入口 Activity 的實例,并執(zhí)行它的生命周期函數(shù)開始,我們的啟動時間統(tǒng)計以及啟動速度優(yōu)化也是從這里開始。下面是 Main Activity 的啟動流程:

-> Application 構(gòu)造函數(shù)
-> Application.attachBaseContext()
-> Application.onCreate()
-> Activity 構(gòu)造函數(shù)
-> Activity.setTheme()
-> Activity.onCreate()
-> Activity.onStart
-> Activity.onResume
-> Activity.onAttachedToWindow
-> Activity.onWindowFocusChanged

如果打 Log 記錄 App 的啟動時間,那么至少要記錄兩個點,一個起始時間點,一個結(jié)束時間點。

起始時間點

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

結(jié)束時間點

結(jié)束時間點理論上要選在 App 顯示出第一屏界面的時候,但是在什么位置 App 顯示出第一屏界面呢?網(wǎng)上很多文章說在 Activity onResume 方法執(zhí)行完成之后,Activity 就對用戶可見了,實際上并不是,一個 Activity 走完onCreate onStart onResume 這幾個生命周期之后,只是完成了應(yīng)用自身的一些配置,比如 Activity 主題設(shè)置 window 屬性的設(shè)置 View 樹的建立,但是其實后面還需要各個 View 執(zhí)行 measure layout draw等。所以在 OnResume 中記錄結(jié)束時間點的 Log 并不準(zhǔn)確,大家可以注意一下上面流程中最后一個函數(shù) 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.
...
*/

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

總結(jié)

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

相關(guān)文章

  • android底層去掉虛擬按鍵的實例講解

    android底層去掉虛擬按鍵的實例講解

    今天小編就為大家分享一篇android底層去掉虛擬按鍵的實例講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-07-07
  • Flutter 移動程序安全性提高的八個建議

    Flutter 移動程序安全性提高的八個建議

    這篇文章主要為大家介紹了Flutter 移動程序安全性提高建議詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • Android實現(xiàn)底部彈出的對話框功能

    Android實現(xiàn)底部彈出的對話框功能

    這篇文章主要介紹了Android實現(xiàn)底部彈出的對話框功能,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • Android 單例模式實現(xiàn)可復(fù)用數(shù)據(jù)存儲的詳細(xì)過程

    Android 單例模式實現(xiàn)可復(fù)用數(shù)據(jù)存儲的詳細(xì)過程

    本文介紹了如何使用單例模式實現(xiàn)一個可復(fù)用的數(shù)據(jù)存儲類,該類可以存儲不同類型的數(shù)據(jù),并提供統(tǒng)一的接口來訪問這些數(shù)據(jù),通過雙重檢查鎖定機(jī)制,該類在多線程環(huán)境下是線程安全的,感興趣的朋友跟隨小編一起看看吧
    2025-02-02
  • 詳解Android的OkHttp包編寫異步HTTP請求調(diào)用的方法

    詳解Android的OkHttp包編寫異步HTTP請求調(diào)用的方法

    OkHttp支持Callback異步回調(diào)來實現(xiàn)線程的非阻塞,下面我們就來詳解Android的OkHttp包編寫異步HTTP請求調(diào)用的方法,需要的朋友可以參考下
    2016-07-07
  • Kotlin協(xié)程概念原理與使用萬字梳理

    Kotlin協(xié)程概念原理與使用萬字梳理

    協(xié)程的作用是什么?協(xié)程是一種輕量級的線程,解決異步編程的復(fù)雜性,異步的代碼使用協(xié)程可以用順序進(jìn)行表達(dá),文中通過示例代碼介紹詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-08-08
  • android自定義view實現(xiàn)推箱子小游戲

    android自定義view實現(xiàn)推箱子小游戲

    這篇文章主要為大家詳細(xì)介紹了android自定義view實現(xiàn)推箱子小游戲,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • ListView下拉列表控件使用方法詳解

    ListView下拉列表控件使用方法詳解

    這篇文章主要為大家詳細(xì)介紹了ListView下拉列表控件的使用方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • Android neon 優(yōu)化實踐示例

    Android neon 優(yōu)化實踐示例

    這篇文章主要為大家介紹了Android neon 優(yōu)化實踐示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • 利用Flutter制作一個會飛的菜單

    利用Flutter制作一個會飛的菜單

    flutter中自帶了drawer組件,可以實現(xiàn)通用的菜單功能,所以本文將嘗試一下通過自定義動畫來實現(xiàn)一個會飛的菜單,感興趣的可以了解一下
    2023-06-06

最新評論