为什么要做启动优化
1、第一体验很重要
2、八秒定律:如果打开需要8秒钟那么用户就会放弃
冷启动是衡量的标准
冷启动流程
click->ipc-process.start->ActivityThread->bindApplication->LifeCycle->ViewRootImpl
优化方向
Application和Activity 生命周期方法是优化的方向 其他的地方其实无法干预
adb命令获取启动时间
adb shell am start -W packagename/首屏Activity
adb shell am start -W com.example.better/.MainActivity
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.example.better/.MainActivity }
Status: ok
Activity: com.example.better/.MainActivity
ThisTime: 364
TotalTime: 364
WaitTime: 374
Complete
WaitTime 表示AMS启动Activity的总耗时
TotalTime 表示所有Activity启动耗时
ThisTime 表示最后一个Activity启动耗时
手动打点
就是从开始时间到ui展示出来的时比如你从application 开始到View画出来时间
比如创建一个类来负责记录时间
class LauncherTimer {
private static long sTime;
public static void startRecord() {
sTime = System.currentTimeMillis();
}
public static void endRecord() {
long cost = System.currentTimeMillis() - sTime;
Log.i("cost", "endRecord: " + cost);
}
}
需要注意的是,应该是View绘制出来作为结束时间,比如可以监听某个View绘制的时候作为结束时间
findViewById(R.id.text).getViewTreeObserver().addOnPreDrawListener(() -> {
LauncherTimer.endRecord();
return true;
});
工具选择
1、Traceview
使用方式
Debug.startMethodTracing("app");
Debug.stopMethodTracing();
它会在应用的目录上生成一个xx.trace 文件 通过Studio打开后可以发现大概长这样
上面滑动部分是你需要选中的时间范围
中间部分会列出所有线程,还有每个做了什么事情,也就是方法调用栈
点击方法可以知道每个方法的耗时
total就是这个方法的耗时,
children 就是子方法的耗时
self 就是自己花费了多长时间
知道了这些就可以进行性能优化
多关注TopDown就可以知道哪些方法耗时了
这个工具比价适合去做开机启动优化,因为开始和结束已经埋在代码里面了。
2、systemtrace
这个应用更适合去做一下某些操作的卡顿
使用方式
TraceCompat.beginSection("better");
TraceCompat.endSection();
运行后执行
python /Users/weihuada/Downloads/platform-tools/systrace/systrace.py -b 32768 -t 5 -a com.example.better -o performance.html sched gfx view wm am app
这个方法是 platform-tools里面自带的方法
这个方法在后续被google移除掉了
https://www.jianshu.com/p/626eaebaa6a8
执行后会输出 performance.html 到当前目录
然后通过浏览器 输入
chrome://tracing/
然后打开这个文件就可以了
启动优化的核心思想是异步优化,让子线程分担主线程任务,并行减少同步事件
但是要注意代码的执行先后顺序
有些代码是不能运行在异步线程的
我们可以用CountDownLatch 这个类去处理代码的先后执行顺序的问题
我们可以比如开四条线程,最后100秒的主线程被分隔到4条线程中
每条线程最后就是25秒 用这个CountDownLatch 就是能先阻塞住
等到四条线程都处理完了再进行下面的操作 但是它不能解决不同线程之间的同步问题
为了解决线程之间的同步问题 我们可以引入线程执行器这里就不展示具体代码。
将不重要的操作放到ui展示出来之后再初始化。
优化总方针
异步、延迟、懒加载
其他黑科技
启动时抑制GC
CPU锁频