1 前言
Android APP 啓動優化是性能優化的重要方向之一,特別是對於原生應用來講,控制在1s內以內對一個APP的競爭力很重要,下面從幾個角度來講APP的啓動優化,先看APP的啓動類別
2 APP啓動類別
參考google官方文檔App startup time,官方對APP啓動主要做了三種分類
1.冷啓動
冷啓動指的是APP從頭開始啓動,沒有創建進程,需要完整的走進程創建,ActivityThread創建,Application創建等生命週期的啓動,冷啓動耗時最多
啓動時分爲以下幾步
1 加載和啓動app
2 加載空白window
3 創建App進程
隨後進行如下步驟
1 創建Application對象,並回調其方法
2 啓動主線程
3 創建MainActivity
4 初始化View和加載佈局
5 佈局屏幕
6 首幀繪製
冷啓動一般流程如下:
2.暖啓動
當應用中的Activity被銷燬,但在內存中常駐時,應用的啓動方式就會變爲暖啓動。相比冷啓動,暖啓動過程減少了對象初始化、佈局加載等工作,啓動時間更短。但啓動時,系統依然會展示一個空白背景,直到第一個Activity的內容呈現爲止。因此暖啓動一般會走Activity的onCreate生命週期,暖啓動耗時較少,一般需要注意在Activity的生命週期中不要做耗時操作即可。
3.熱啓動
相比暖啓動,熱啓動時應用做的工作更少,啓動時間更短。熱啓動產生的場景很多,常見如:用戶使用返回鍵退出應用,然後馬上又重新啓動應用。熱啓動較快,一般需要注意在onResmue中不要做耗時操作
對於系統流程我們一般無法改變,因此對於三方應用來說,APP啓動優化的主要方向在Application的生命週期和Activity的生命週期中
3 APP啓動測量
前面講了APP啓動的類別,現在要講如何粗略或者詳細的測量一個APP的啓動時間,一般來說有以下幾種辦法
1 adb 命令測量
adb shell am start –W packageName/首屏Activity
例如:
adb shell am start –W com.qiyei.mall/com.qiyei.mall.ui.activity. MainActivity
執行如下:
MainActivity 是首頁,HomeActivity是主頁
ThisTime: 最後一個Activity啓動耗時
TotalTime: 啓動所有Activity耗時
WaitTime: AMS啓動Activity耗時
2 ActivityManager中日誌打印
ActivityManager中會打印啓動activity的時間
ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms (total +1m22s643ms)
相關的代碼如下:
ActivityRecord#reportLaunchTimeLocked()
private void reportLaunchTimeLocked(final long curTime) {
final ActivityStack stack = getStack();
if (stack == null) {
return;
}
final long thisTime = curTime - displayStartTime;
final long totalTime = stack.mLaunchStartTime != 0
? (curTime - stack.mLaunchStartTime) : thisTime;
if (SHOW_ACTIVITY_START_TIME) {
Trace.asyncTraceEnd(TRACE_TAG_ACTIVITY_MANAGER, "launching: " + packageName, 0);
EventLog.writeEvent(AM_ACTIVITY_LAUNCH_TIME,
userId, System.identityHashCode(this), shortComponentName,
thisTime, totalTime);
StringBuilder sb = service.mStringBuilder;
sb.setLength(0);
sb.append("Displayed ");
sb.append(shortComponentName);
sb.append(": ");
TimeUtils.formatDuration(thisTime, sb);
if (thisTime != totalTime) {
sb.append(" (total ");
TimeUtils.formatDuration(totalTime, sb);
sb.append(")");
}
Log.i(TAG, sb.toString());
}
mStackSupervisor.reportActivityLaunchedLocked(false, this, thisTime, totalTime);
if (totalTime > 0) {
//service.mUsageStatsService.noteLaunchTime(realActivity, (int)totalTime);
}
displayStartTime = 0;
stack.mLaunchStartTime = 0;
}
可以看到打印的是,這個時間從應用啓動(創建進程)開始計算,到完成視圖的第一次繪製的時間
3 手動打點
這個思想也比較簡單,由於應用層能接觸到的最早方法是Application#attachBaseContext()而結束時間,我們可以認爲是Activity#onWindowFocusChanged或者View的真正繪製完成,因此我們可以在attachBaseContext記錄一下時間,在onWindowFocusChanged中或者View繪製完成後記錄結束時間,只是需要注意怎麼處理View的onDraw監聽問題
4 Systrace測量
這個可以參考官方文章systrace來進行操作,注意systrace需要python環境,因此需要先搭建好python環境。下面是一個systrace的例子
可以看到,systrace可以看到更多的系統調用過程,例如這裏可以看到進程Zygote創建和ActivityThread的初始化時間等,有助於分析啓動時當時系統的狀態。
這一篇就介紹到這,下一篇會介紹TraceView和Systrace的簡單使用