app的啟動模式分為三種:
1.冷啟動
冷啟動耗時最久,衡量的保準最多
Click Event - IPC - Process.start - ActivityThread - bindApplication - LifeCycle - ViewRootImpl
使用者在桌面點選app 發起一個IPC操作,通過Process.start 然後建立ActivityThread,是每一個單獨app程序的入口,訊息迴圈的建立,然後通過反射建立application呼叫於application相關的生命週期,最後就是建立我們常用的Activity的生命週期,當Activity的生命週期完畢後,就會進入到ViewRootImpl進行真正的介面繪製。
2.熱啟動
最簡單,最快
後臺 - 前臺
3.溫啟動
相對冷啟動比較快一些
LifeCycle
根據網際網路行業的8秒原則,我們需要控制冷啟動的啟動速度,那麼我們來看冷啟動都做了一些什麼呢?
冷啟動:
1.啟動app
2.載入空白頁(圖片替換)
3.建立程序
4.建立application
5.啟動出執行緒
6.建立MainActivity
7.載入佈局
8.佈置螢幕
9.首幀繪製
檢視啟動耗時:
方法1:
命令:adb命令觀察app啟動的時間 (線下使用,無法帶到線上)
adb shell am start -W -n 包名/類名 或者 adb shell am start -W 包名/類名
比如我自己的app:adb shell am start -W -n com.yinyan.ywf.app/com.cfs.app.ui.activity.sp.SpActivity
macdeMac-mini:~ mac$ adb shell am start -W -n com.yinyan.ywf.app/com.cfs.app.ui.activity.sp.SpActivity
Starting: Intent { cmp=com.yinyan.ywf.app/com.cfs.app.ui.activity.sp.SpActivity }
Status: ok
Activity: com.yinyan.ywf.app/com.cfs.app.ui.activity.sp.SpActivity
ThisTime: 2654 最後Activity啟動耗時
TotalTime: 2654 所有Activity啟動的耗時(包含閃屏)
WaitTime: 2673 AMS啟動Activity的總耗時
Complete
方法2:手動打點(線上捕獲)
/**
* 啟動時間捕獲 手動打點
*/
public class LaunchTimer {
private static long sTime;
public static void startRecord(){
sTime = System.currentTimeMillis();
}
public static void endRecord(){
long cost = System.currentTimeMillis() - sTime;
Logger.i("cost = ",cost);
}
}
啟動時間記錄,在Application的attachBaseContext()方法中呼叫 LaunchTimer.startRecord()
結束的呼叫建議放在自己adapter的第一個item載入出來,或者activity渲染完畢的生命週期中,不要放在首幀回撥(onWindowFocusChanged)的位置,因為首幀回撥未必繪製完畢了頁面,是不準確的。
現在我們形成對比 我們先看看SophixApplitcation
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
LaunchTimer.startRecord();
// 如果需要使用MultiDex,需要在此處呼叫。
// MultiDex.install(this);
initSophix();
}
接下來對比一下首幀繪製和FeedShow之後的啟動時間
IndexActivity
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
LaunchTimer.endRecord("onWindowFocusChanged");
freshFragmnet();
}
IndexActivity - HomeFragment - BusinessAdapter中的第一個Feed載入出來的時候
mHasRecorded自己宣告一下即可 布林型別
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
Holder holder = (Holder) viewHolder;
/**
* 啟動首次繪製時間統計
*/
if(position == 0 && !mHasRecorded){
mHasRecorded = true;
holder.ll_business.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
holder.ll_business.getViewTreeObserver().removeOnPreDrawListener(this);
LaunchTimer.endRecord("FeedShow");
return true;
}
});
}
}