启动时间测量方式
- adb 命令
- 手动打点
adb 命令
使用命令行方式统计多次启动某个Activity的平均用时可以在shell中执行如下指令:
adb shell am start -W packageName/首屏Activity
注意:使用该命令时要在启动相应模拟器并安装测试的APP包;-W 要大写。
示例如下图所示:
ThisTime
:最后一个 Activity 启动耗时
TotalTime
:所有 Activity 启动耗时
WaitTime
:AMS 启动 Activity 的总耗时
缺点:
- 没有在 AndroidManifest.xml 对应的 Activity 声明中指定 <intent-filter> 或者属性没有 android:exported="true" 的 Activity 不能使用这种命令行的形式计算启动时间。
- 线下使用方便,不能带到线上
手动打点
启动时埋点,启动结束埋点,二者差值
下面创建一个 LaunchTimer 类来记录APP启动和结束的时间差
class LaunchTimer {
companion object {
private var time: Long = 0L
/**
* 记录开始计时时间
*/
fun startRecord() {
time = System.currentTimeMillis()
}
/**
* 记录启动结束的计时时间
*/
fun endRecord() {
endRecord("")
}
fun endRecord(msg: String) {
val cost = System.currentTimeMillis() - time
LogUtils.i("$msg cost $cost")
}
}
}
在 Application 的 attachBaseContext
方法中记录启动开始时间,如下所示
class PerformanceApp : Application() {
companion object {
private var sApplication: Application? = null
fun getApplication(): Application? {
return sApplication
}
}
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
//开始时间的记录
LaunchTimer.startRecord()
}
override fun onCreate() {
super.onCreate()
sApplication = this
}
}
在记录 APP 启动结束时间是要注意不要在 onWindowFocusChanged 方法中记录。
onWindowFocusChanged
只是Activity的首帧时间。是 Activity 首次绘制的时间,不能代表界面移一定展现出来了。
真实数据展示,Feed 第一条展示出来,这样才算是启动结束了。所以要在真实的数据展示出来后记录启动结束时间
下面对两种方式作比较:
class MainActivity : AppCompatActivity() {
private var mNewsAdapter: NewsAdapter? = null
var mItems: MutableList<NewsItem> = ArrayList()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
LaunchTimer.endRecord("onWindowFocusChanged")
}
}
public class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder> {
/**
* 是否已经统计过
*/
private boolean mHasRecorded;
@Override
public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
//onBindViewHolder 回调多次,而只统计一次,加个变量标识
if (position == 0 && !mHasRecorded) {
mHasRecorded = true;
holder.layout.getViewTreeObserver()
.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
holder.layout.getViewTreeObserver().removeOnPreDrawListener(this);
LaunchTimer.Companion.endRecord("FeedShow");
return true;
}
});
}
}
}
运行结果如下图:
可以看到差距还是比较大的。
网友评论