Android啟動時間優化檢視及冷啟動時間優化優化
測量Activity 的啟動時間
如何獲得app的啟動時間?
我也在想這個問題。
當我在framework 程式碼上做這類測量的時候,我可以精確的得出我需要的東西。但是非framework 開發者如何從普通構建獲得自己需要的資訊呢?
一 、直接看log
幸運的是,這個資訊是存在的,如果你執行的是4.4(Kitkat)以後的版本,你就可以得到。
你只要啟動你的activity ,然後直接在logcat裡面檢視,尋找這樣的log:
1 |
ActivityManager: Displayed com.android.myexample/.StartupTiming: +768ms
|
這個資訊在activity 視窗完成所有的啟動事件之後,第一次繪製的時候輸出。這個時間包括了從啟動程序到第一次佈局與繪製的所有時間。這基本上是你需要知道的主要時間。它不包含使用者點選app圖示然後系統開始準備啟動activity的時間,這是ok的,因為作為一個開發者你無法影響這個時間,所以沒有必要去測量它。
相反,它包含的是在啟動時載入程式碼,初始化類所用的時間。裡面都是你真正想測量的時間,因為它們才是你能優化也應該去優化的東西。
二、呼叫Activity的reportFullyDrawn()方法
前面所提到的 'Displayed' 時間是自動報告的。 快速測量啟動初始化需要多久。但是假如你還非同步載入一些其它的內容,想知道所有的東西載入完成,繪製需要多久該怎麼做呢?
這種情況下,你就需要呼叫Activity的reportFullyDrawn()。它將在log裡報告從apk初始化(和前面Displayed的時間是一樣的)到reportFullyDrawn() 方法被呼叫用了多長時間。
reportFullyDrawn()方法顯示的log也是類似這樣:
ActivityManager: Displayed com.android.myexample/.StartupTiming: +768ms
譯者注:在4.4上呼叫reportFullyDrawn()方法會崩潰(但是log還是能正常列印),提示需要UPDATE_DEVICE_STATS許可權 ,但是這個許可權只有系統app才能授權。解決的辦法是這樣呼叫:
1 2 3 4 |
try {
reportFullyDrawn();
} catch (SecurityException e){
}
|
三、使用screenrecord命令
還有一種測量啟動時間的方法也值得一提,那就是screenrecord命令。
首先啟動帶—bugreport選項(它可以在frames 中新增時間戳-應該是L中的特性)的screenrecord 命令:
1 |
$ adb shell screenrecord --bugreport /sdcard/launch.mp4
|
然後點選app的圖示,等待app顯示,ctrl-C screenrecord, 使用adb pull命令把檔案匯出到電腦。
1 |
$ adb pull /sdcard/launch.mp4
|
現在你可以開啟錄製視訊看看發生了什麼。你需要一個能逐幀檢視的視訊播放器(mac上的Quicktime 就可以,不清楚其它os上什麼播放器這個功能最好使)。現在逐幀播放,注意視訊的上方有一個frame 時間戳。
一直往前直到你發現app圖示高亮了為止。這個時候系統已經處理了圖示上的點選事件,開始啟動app了,記錄下這一幀的時間。繼續播放幀直到你看到了app整個UI的第一幀為止。根據不同情況(是否有啟動視窗,是否有啟動畫面等等),事件和視窗發生的實際順序可能會有不同。對於一個簡單的app來說,你會首先見到啟動視窗,然後漸變出app真實的UI。在你看到UI上的任何內容之後,你應該記錄下第一幀,這時app完成了佈局和繪製,準備開始顯示出來了。同時也記錄下這一幀所發生的時間。
現在把這兩個時間相減 ((UI displayed) - (icon tapped)); 得到app從點選到繪製就緒的所有時間。雖然這個時間包含了程序啟動之前的時間,但是至少它可以用於跟其他app比較。
四 通過外部調起應用(shell am)的方法來獲取啟動時間。
adb shell am start -W -n yourpakagename/MainActivity
此法獲取的啟動時間非常精準,可精確到毫秒。
五 通過ActivityManager輪訓來實現獲取啟動時間
ActivityManager am = (ActivityManager) getSystemService(this.ACTIVITY_SERVICE); List<RunningAppProcessInfo> appinfo = am.getRunningAppProcesses(); for (RunningAppProcessInfo runningAppProcessInfo : appinfo) { if (runningAppProcessInfo.processName.equals("yourpakagename")) { Log.e("TAG", System.currentTimeMillis() + ""); } }
Android冷啟動時間優化
冷啟動時間是指當用戶點選你的app那一刻到系統呼叫Activity.onCreate()之間的時間段。在這個時間段內,WindowManager會先載入app主題樣式中的windowBackground做為app的預覽元素,然後再真正去載入activity的layout佈局
冷啟動時間優化
知道了Android冷啟動時間的原理之後,就可以通過一些小技巧來對冷啟動時間進行優化,從而讓你app載入變得”快“一些(視覺體驗上的快)。我們可製作一個啟動Activity的背景樣式的.9圖片,然後把這個.9圖片做為windowBackground。
-
首先
git clone https://github.com/DreaminginCodeZH/MaterialColdStart
-
由於該庫中引用了子模組 AndroidSVGScripts, 所以我們需要把該子模組也update下來,否則無法執行。但是作者定義該子模組的時候使用了ssh協議,所以會導致我們無法update,這裡我們要先修改
.gitmodules
檔案將裡面所有的[email protected]:
改為https://github.com/
就可以了,然後執行git submodule init
和git submodule update
命令就可在把子模組update下來了 -
在生成.9圖片之前,我們還需要根據自己的專案修改生成.9圖片的配置檔案,開啟
colors.conf
檔案,可以配置statusbar、actionbar、background的顏色等,修改raw-xxx目錄下的window_background_statusbar_toolbar_tab.9.shsvg.conf
檔案可以配置statusbar、actionbar的高度等 -
最後執行
./gen-png.sh
命令,就可以在gen目錄下生成我們所需的.9圖片了
圖片製作好之後,我們就可以用它做為app冷啟動階段的預覽元素,如下設定:
-
為啟動的Activity自定義一個Theme
1 2 3 <style name=
"AppTheme.Launcher"
>
<item name=
"android:windowBackground"
>@drawable/window_background_statusbar_toolbar_tab</item>
</style>
-
將新的Theme應用到設定到
AndroidManifest.xml
中1 2 3 4 5 6 7 8 9 <activity
android:name=
".MainActivity"
android:theme=
"@style/AppTheme.Launcher"
>
<intent-filter>
<action android:name=
"android.intent.action.MAIN"
/>
<category android:name=
"android.intent.category.LAUNCHER"
/>
</intent-filter>
</activity>
-
由於給MainActivity設定了一個新的Theme,這樣做會覆蓋原來的Theme,所以在MainActivity中需要設定回原來的Theme
1 2 3 4 5 6 7 8 9 10 11 |
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// Make sure this line comes before calling super.onCreate().
setTheme(R.style.AppTheme);
super .onCreate(savedInstanceState);
}
}
|
效果預覽
第一張是啟用了冷啟動優化,第二張是沒有啟用冷啟動優化