不平凡軟件,始于2014

首頁 | 加入收藏 | 設為首頁

15565077981

您當前的位置:首頁 >  軟件開發(fā)知識>詳細

【鄭州軟件開發(fā)】Android 性能優(yōu)化--啟動時間優(yōu)化

發(fā)布者: 鄭州軟件開發(fā) 07-17

請保持淡定,分析代碼,記?。盒阅芎苤匾?

啟動時間優(yōu)化

毫無疑問,應用的啟動速度越快越好。

本文可以幫助你優(yōu)化應用的啟動時間:首先解釋啟動過程內部機制;然后討論如何分析啟動性能;最后,描述了一些常見的影響啟動時間的問題,并就如何解決這些問題給出一些提示。

第 1 部分:啟動過程內部機制

應用的啟動有三種狀態(tài),不同狀態(tài)的啟動時長是不一樣的。三種狀態(tài)分別為:冷啟動(cold start),熱啟動(warm start),溫啟動(lukewarm start)。冷啟動即應用從零開始加載運行,而其它則是應用從后臺運行回到前臺運行。建議您始終基于冷啟動的假設進行優(yōu)化,因為這樣做同樣提升了另兩種啟動狀態(tài)的表現。

要使得應用能快速啟動,需要先理解應用以不同狀態(tài)啟動時,系統(tǒng)和應用內發(fā)生了什么,以及它們如何相互作用。

1) 冷啟動(cold start)

冷啟動指系統(tǒng)沒有該應用的進程,直到開啟應用才創(chuàng)建出應用程序的進程。冷啟動一般指的就是應用在開機后或者系統(tǒng)停止應用后的第一次啟動。因為系統(tǒng)和應用程序在該狀態(tài)下啟動需要做更多的工作,所以減少它的啟動時間的挑戰(zhàn)是最大的。

冷啟動初始時,系統(tǒng)完成三個任務:

  • 啟動和加載應用(這里泛指的是應用本身)
  • 創(chuàng)建應用的專屬進程
  • 啟動后立刻顯示啟動窗口(通常是個空白屏)

一旦系統(tǒng)創(chuàng)建了應用的專屬進程,該進程開始創(chuàng)建應用:

  1. 創(chuàng)建應用對象
  2. 啟動主線程(MainThread)
  3. 創(chuàng)建 Main Activity
  4. 加載視圖(Inflating views)
  5. 渲染布局(Laying out)
  6. 執(zhí)行初始繪制

一旦應用完成了第一次繪制,系統(tǒng)進程就把當前顯示的啟動窗口切換為應用的界面,這時用戶就可以開始使用應用了。

下圖展示了系統(tǒng)和應用的啟動時相互之間的關系:

系統(tǒng)和應用啟動流程

以上流程中的大部分由系統(tǒng)來控制,需要關注性能問題的地方往往出現在 Application 和 Activity 的創(chuàng)建(onCreate)過程中。

a) 創(chuàng)建 Application

Application onCreate

當你的應用啟動,屏幕立即出現的空白屏幕,將在應用完成首屏的繪制時,切換為應用首屏,然后允許用戶開始與應用進行交互。

如果你在應用中重載了 Application.oncreate(),系統(tǒng)將先調用應用的 onCreate()方法。大型的 App 通常會在這里做大量的通用組件、SDK 的初始化操作。

然后應用程序會生成主線程,也被稱為 UI 線程,并開始創(chuàng)建 Main Activity。

在這之后,系統(tǒng)和應用按各自的生命周期運行著。

b) 創(chuàng)建 Activity

Paste_Image.png

應用創(chuàng)建 Activity:

  1. 初始化
  2. 調用構造函數
  3. 調用當前生命周期的回調方法,例如 Activity.onCreate()

通常情況下,onCreate() 方法對加載時間的影響最大,因為它執(zhí)行了開銷最重的工作:加載、渲染,以及初始化 Activity 所需要的對象,如果布局過于復雜很可能導致嚴重的啟動性能問題。

2) 熱啟動(warm start)

應用程序的熱啟動比冷啟動開銷低。在熱啟動中,系統(tǒng)只是需要把 Activity 切換到前臺運行。如果應用的該 Activity 之前駐留在內存中,那么應用程序就不用重新初始化對象和渲染布局。

但是,如果由于響應了低內存事件,例如在 onTrimMemory() 方法中清除了資源對象,那么這些對象就需要在熱啟動時重新創(chuàng)建。

熱啟動與冷啟動的顯示情況是一致的:系統(tǒng)進程顯示空白屏幕,直到應用程序已經完成 Activity 的渲染。即如果從內存中直接切換,則不會顯示空白屏幕,如果內存內容被清除,將顯示空白屏幕等待渲染完成。

3) 溫啟動(lukewarm start)

溫啟動為冷啟動的過程操作的子集:這代表開銷比熱啟動稍大。以下這些情況可以認為是溫啟動:

  1. 用戶退出應用,但隨后重新啟動它。應用的進程還在運行,但應用必須從新從 onCreate()開始創(chuàng)建 Activity。

  2. 系統(tǒng)從內存中清除了應用(非用戶主動),然后用戶重新啟動它。進程和 Activity 需要重新啟動,但 onCreate()將接收到保存狀態(tài)的 Bundle。事實上,savedInstanceState 的保存在用戶未主動銷毀 Activity 時系統(tǒng)就會調用。

第 2 部分:剖析啟動性能

為了正確評估啟動時的表現,你需要跟蹤應用啟動到顯示需要多長時間。下圖展示了應用初始顯示的時間和完全顯示的時間的定義。

兩種顯示時間

1) 初始顯示的時間

a) Displayed

從 Android 4.4(API 19) 開始,logcat 的輸出包括了一行 Displayed 的值。這個值表示了應用啟動進程到 Activity 完成屏幕繪制經過的時間。經過的時間包括以下事件,按順序為:

  1. 啟動進程
  2. 初始化對象
  3. 創(chuàng)建和初始化 Activity
  4. 布局渲染
  5. 完成第一次繪制

報告的日志行看起來類似于下面的例子:

I/ActivityManager: Displayed com.android.contacts/.activities.PeopleActivity: +612ms
  • 1

如果您在終端使用 logcat,可以直接找到這一行,當然,為了方便需要使用 grep 進行查找。而如果使用 Android Studio 查看,你必須在你的 logcat 視圖中禁用過濾器,因為這是系統(tǒng)打的日志而不是應用本身。一旦您完成了過濾器設置,就可以輕松地搜索到該行查看時間。下圖 展示了如何禁用過濾器,及 logcat 窗口顯示 Displayed 時間的例子。

Android Studio logcat 窗口

Displayed 時間顯示的是到第一次繪制的時候,它并不包括不被布局文件及初始化對象所引用的資源的加載時間,因為這個加載是一個內部過程,不阻塞應用初始內容的顯示。

b) ADB Shell Activity Manager

你也可以使用 ADB Shell Activity Manager 測量啟動到顯示的時間。下面是一個例子:

adb shell am start -S -W com.android.contacts/.activities.PeopleActivity -c android.intent.category.LAUNCHER -a android.intent.action.MAIN 
  • 1
  • 2
  • 3

你的終端窗口就像顯示 Displayed 一樣地顯示如下內容:

Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.android.contacts/.activities.PeopleActivity } Status: ok Activity: com.android.contacts/.activities.PeopleActivity ThisTime: 701 TotalTime: 701 WaitTime: 718 Complete
				
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

通過可選參數-c 和-a 可以指定 Intent 的 <category> 和 <action>。

2) 完全展示的時間

a) reportFullyDrawn()

你可以使用reportFullyDrawn()方法來測量應用啟動到所有資源和視圖層次結構的完整顯示之間所經過的時間,這在應用使用延遲加載的情況下是很有用的。

在延遲加載時,應用在初始的繪圖之后,異步加載資源,然后更新視圖。如果由于延遲加載,應用的初始顯示并不包括所有的資源,你可能會考慮將所有的資源和視圖的完全加載和顯示作為一個單獨的指標。例如,您的用戶界面可能已經完成了文本的加載,但又必須從網絡獲取圖像。

為了解決這個問題,你可以手動調用reportFullyDrawn(),讓系統(tǒng)知道你的 Activity 完成了它的延遲加載。當您使用此方法,logcat 將顯示出從創(chuàng)建應用對象到調用 reportFullyDrawn()方法的時間。下面是 logcat 的輸出的例子:

system_process I/ActivityManager: Fully drawn {package}/.MainActivity: +1s54ms
													
  • 1

b) screenrecord

還有一種測量啟動時間的方法值得一提,因為這種方法雖然繁瑣但可以很直觀查看起止位置的時間,那就是通過screenrecord命令。該命令可以直接錄制屏幕,通過以下命令啟動:

adb shell screenrecord --bugreport /sdcard/launch.mp4 
													
  • 1

在手機上操作,點擊 App,等待其顯示,必要時可以多等待一會兒,然后使用Ctrl + c停止命令,就得到了想要的視頻了。使用命令導出視頻:

adb pull /sdcard/launch.mp4
													
  • 1

接著就可以使用一個能逐幀查看的視頻播放器——例如 QuickTime 播放器來查看視頻,一般地,認為 App 的圖標高亮時為計時的起點,記錄此刻到你想要的停止的位置之間的時間就可以了。簡單來說,就是錄制一個視頻,使用逐幀查看的視頻播放器方便地記錄下你想查看的任意起止時刻。

如果你發(fā)現啟動時間比預期要慢,你可以嘗試著找出啟動過程中的瓶頸。

3) 識別性能瓶頸

有兩個很好的方法可以用來來定位問題:Method Tracer 工具和 Systrace 工具。

a) Method Tracer 工具

在 Android Studio 的 CPU Monitor 欄中,提供了 Method Tracer 工具。

Android Monitor 中的 Method Trace

首先需要啟動要監(jiān)控的應用,在 Android Studio 下方的 Android Monitor 中選擇該應用的進程(圖中長方框位置),就可以看到 Memory Monitor / CPU Monitor / Network Monitor 都開始工作起來。

如果要使用 Method Trace 功能,只需要點擊 Start Method Tracing(圖中小方框),在手機上進行操作之后,再次點擊它停止 Method Trace,稍等片刻就能在工程的 captures 文件夾中找到 .trace 文件了。

由以上流程可以知道對于冷啟動而言是無法在正確的時間啟動該工具以獲得日志信息的。這種情況下可以在代碼中合適的位置,例如onCreate()和onResume()中,添加android.os.Debug.startMethodTracing()和android.os.Debug.stopMethodTracing()方法來生成 trace 文件,該文件生成在 sdcard 根目錄下或者應用的讀寫目錄中。

Note: 運行 Method Trace 將明顯地影響運行應用的效果。 Method Trace 應該用來了解程序的流程及方法的運行時間比例,其計時時間不可直接作為應用性能的表現。

使用 Android Studio 打開 trace 文件,如果是 CPU Monitor 中生成了 trace 文件,Android Studio 會自動打開它,你將得到如下形式的圖片:

Android Studio 中 trace 文件的展示

列名 具體含義
Name 方法名
Invocation Count 方法調用次數
Inclusive Time (microseconds) 該方法及其調用的子方法的耗時
Exclusive Time (microseconds) 該方法(不包含調用的子方法)的耗時

圖表的 x 坐標可以選擇Wall Clock Time或者Thread Time,其中前者表示方法調用到返回結果真實的 CPU 時間,后者表示線程調度的時間,如果線程不連續(xù)執(zhí)行,那么被中斷的時間將被排除,所以將小于前者的統(tǒng)計。

也可以使用 DDMS 打開 trace 文件,其展示的視圖如下所示:

DDMS 中 trace 文件的展示

各列名稱及其含義與 Android Studio 的圖示基本類似。

還可以使用 dmtracedump 工具解析生成 html 文件如下圖(dmtracedump 可以生成圖片,但往往混亂到看不出順序,有興趣的可以自行查閱相關資料):

dmtracedump 解析 trace 文件

從以上三種方式展示的 trace 文件結果來看,結果中包含了 JDK 函數,第三方庫函數,以及 Android SDK 中函數,如果想僅分析應用中的方法調用順序信息,可以根據 trace 文件過濾出當前應用下的方法信息。目前 GitHub 上有一個 Windows 平臺下的分析應用方法耗時的 swing 工具,其使用方法很簡單:

  • 將 sdk\platform-tools 下的 dmtracedump 添加到系統(tǒng)環(huán)境變量
  • 基于 jdk 1.8 環(huán)境運行 Method-trace-analysis.jar
  • 直接導入 .trace 文件,一鍵分析(注意:trace 文件路徑不要包含空格)

該工具的思路基于:一個能讓你了解所有函數調用順序以及函數耗時的 Android 庫(無需侵入式代碼),該庫核心就是 2 個 build.gradle 中的 task 基于 dmtracedump 工具對 trace 文件進行解析、過濾。

Method Trace Tool 得到了良好的展示效果,如圖:

Method Trace Tool 中 trace 文件的展示

以上 trace 文件的幾種展示方式可以讓你了解到關于應用中方法的調用順序及耗時信息(注意:該耗時信息不代表真正使用場景下的耗時),基于以上信息可以分析出一個方法或者一個環(huán)節(jié)是否成為性能瓶頸。

b) Systrace 工具

另一個跟蹤的方法就是 Systrace 的使用了。了解更多,請參閱 Trace 功能的參考文檔,以及 Systrace 工具的介紹。

返回列表

上一篇

鄭州短視頻小程序開發(fā)制作短視頻小程序

下一篇

鄭州軟件開發(fā)之你所不知道的企業(yè)文化--產品精神

相關新聞

相關案例