亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

 更新時(shí)間:2016年08月10日 17:49:27   作者:?jiǎn)蔚锻炼? 
當(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ù)庫(kù)的建立,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í)間還是很簡(jiǎn)單的,通過命令行方式即可:

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)用的入口 Activity, ActivityManagerService 發(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í)間的全部?jī)?nèi)容,本文的內(nèi)容小編覺得還是很重要的,還是那句話:工欲善其事,必先利其器,準(zhǔn)備工作做的充分,做事自然有理有據(jù)。希望本文的內(nèi)容對(duì)大家有所幫助。

相關(guān)文章

最新評(píng)論