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的简单使用