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

安卓(Android)開發(fā)之統(tǒng)計(jì)App啟動(dòng)時(shí)間

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

前言

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

一、啟動(dòng)類型

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

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

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

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

二、本地啟動(dòng)時(shí)間的統(tǒng)計(jì)方式

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

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

ThisTime 表示一連串啟動(dòng) Activity 的最后一個(gè) Activity 的啟動(dòng)耗時(shí);

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

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

三、線上啟動(dòng)時(shí)間的統(tǒng)計(jì)方式

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

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

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

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

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

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

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

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

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

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

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

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

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

-> 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 的啟動(dòng)時(shí)間,那么至少要記錄兩個(gè)點(diǎn),一個(gè)起始時(shí)間點(diǎn),一個(gè)結(jié)束時(shí)間點(diǎn)。

起始時(shí)間點(diǎn)

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

結(jié)束時(shí)間點(diǎn)

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

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

總結(jié)

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

相關(guān)文章

  • android底層去掉虛擬按鍵的實(shí)例講解

    android底層去掉虛擬按鍵的實(shí)例講解

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

    Flutter 移動(dòng)程序安全性提高的八個(gè)建議

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    利用Flutter制作一個(gè)會(huì)飛的菜單

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

最新評(píng)論