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;
}
});
}
}