App性能优化:启动优化篇

App性能优化:启动优化篇

本篇主要探讨App启动优化相关内容

1、启动分类

  • 冷启动
  • 热启动
  • 温启动

冷启动

1.冷启动流程图
App性能优化:启动优化篇_第1张图片

热启动

最快:后台切换到前台

温启动

较快:重新执行Activity的生命周期,不会重新创建Application

冷启动相关任务

冷启动之前:

  • 启动App
  • 加载空白Window
  • 创建进程

随后任务:

  • 创建Application
  • 启动主线程
  • 创建MainActivity
  • 加载布局
  • 布置屏幕
  • 首帧绘制
优化方向:

在Application和Activity生命周期阶段,是我们能比较好干预的阶段,也是优化的重点阶段

2、启动时间的测量

  1. Adb命令的方式
    Adb shell am start -W packagename/packagename.首屏Activity
    效果图如下:
    App性能优化:启动优化篇_第2张图片
    thisTime:最后一个Activity启动耗时
    totalTime:所有Activity启动耗时
    waitTime:AMS启动Activity的总耗时
手动打点

误区:OnWindowFocusChanged只是首帧时间
正解:真实数据展示的时间,列表第一条数据展示出来:

btn_start.viewTreeObserver.addOnDrawListener(object:ViewTreeObserver.OnDrawListener{
            override fun onDraw() {
                val endTime=System.currentTimeMillis()
            }
        })

3、启动优化工具的使用

一、TraceView
二、SysTrace

TraceView 工具

TraceView的特点:

  1. 图形的形式展示执行时间、调用栈
  2. 信息全面,包含所有线程

TraceView的使用的使用:

  • Debug.startMethodTracing(“App”);
  • Debug.stopMethodTracing();
  • 生成文件的位置:以Android 9 模拟器为例,文件位于:
    mnt/sdcard/Android/data/packagename/files/App.trace
    打开.trace后,Android studio 会通过Profiler分析文件
    生成cpu调用的图形信息,左侧会显示各个线程我们选中main线程
    下面就是main线程在时间范围00.000-00.298之间的图表
  1. Call Chart
    水平轴表示函数调用(或调用方)的时间,并沿垂直轴显示其被调用者。 对系统 API 的函数调用显示为橙色,对应用自有函数的调用显示为绿色,对第三方 API(包括 Java 语言 API)的函数调用显示为蓝色。 下图展示了一个调用图表示例,并描绘了给定函数的 Self time、Children time 以及总时间的概念。
    相关函数可以右键Jump to source
    App性能优化:启动优化篇_第3张图片

  2. Flame Chart
    Flame Chart 标签提供一个倒置的调用图表,其中水平轴不再代表时间线,它表示每个函数相对的执行时间。
    App性能优化:启动优化篇_第4张图片

  3. Top Down
    Top Down 标签显示一个函数调用列表,在该列表中展开函数节点会显示函数调用的子函数
    App性能优化:启动优化篇_第5张图片

traceview注意事项
  1. 运行时开销很大,整体都会变慢
  2. 可能会带偏优化方向
  3. traceview与cpu Profiler,老版本使用traceView,新版本就是用Profiler打开的trace文件,Profiler更加强大,同时可以做内存,网络等更多的更多的性能监控。
  4. traceView可以进行手动打点,进行更加精确的监控
  5. wall clock time和Thread Time,wall time是占用的cpu的时间,thread time是线程执行的时间,cpu时间是小于线程时间的。
  6. .trace文件默认最大是8M的大小,如果初始化任务较多,最好自定义文件大小,方便精确监控
systrace工具的使用

参考官网:systrace官方指南

  • systrace:结合android内核的数据,生成Html报告
  • API 18以上使用,推荐使用TraceCompat
  • systrace 是一段python脚本,通过终端执行命令:首先进入strace.py所在目录,mac在Users/username/Library/Android/sdk/platform-tools/systrace目录下,然后运行python命令:
    python systrace.py -b 10240 -t 5 -a 包名 -o hdperformance.html sched gfx view wm am app
    • -b:指定buffer大小
    • -t:指定时间 5s
    • -a:指定包名
    • -o:指定输出文件的名称
systrace监控启动时间

1、 在application的oncreate里面添加代码:

TraceCompat.beginSection("appOnCreate");
//初始化操作
...
TraceCompat.endSection();

App性能优化:启动优化篇_第6张图片
2、通过命令行开启systrace
App性能优化:启动优化篇_第7张图片
执行命令后打开app,即可监听到启动信息,会在systrace目录下生成一个*.html文件。通过浏览器打开hdperformance.html文件
App性能优化:启动优化篇_第8张图片

trace.html文件分析
  1. 在左侧根据包名找到我们的进程

  2. 在左侧点击Frames下面的UI Thread

  3. 操作快捷键WSAD,放大缩小,左右移动,找到在代码中设置的tag:appOnCreate

  4. 点击tag,在点击M选中这一部分
    App性能优化:启动优化篇_第9张图片

  5. 选中后可以看到cpu时间和线程时间
    App性能优化:启动优化篇_第10张图片

  6. 上面可以看到CPU 各个核心的使用情况
    App性能优化:启动优化篇_第11张图片

systrace特点
  1. 轻量级,开销小
  2. 直观反应cpu利用率
  3. cpu time 和wall time的区别:cputime小于wall time,我们真正需要关注的优化点在cpu time

4、优雅获取方法耗时

AspectJ 面向切面编程
  • classpath ‘com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.0’
  • implementation ‘org.aspectj:aspectjrt:1.8.+’
  • apply plugin :‘android-aspectjx’
JointPoint
  • 程序运行时候的执行点
  • 获取、设置变量
  • 类初始化
Advice
  • 一种Hook,要插入代码的位置
  • Before:PointCut之前执行
  • After:PointCut之后执行
  • Around:PointCut之前之后分别执行
AspectJ 使用实例

配置好上面的aspectj插件后,编写如下aspectj代码,即可监听application启动时候每个方法的耗时:

@Aspect
public class PerformanceAop {
    @Around("call(* packagename.ApplicationContext.**(..))")
    public void getTime(ProceedingJoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        String name = signature.getName();
        long time = System.currentTimeMillis();
        try {
            joinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        Log.d("PerformanceAop", name + "__cost=" + (System.currentTimeMillis() - time));
    }
}

执行效果如下:
App性能优化:启动优化篇_第12张图片

AOP的优点
  1. 无侵入性
  2. 修改方便

5、异步优化最优解-启动器

核心思想:子线程分担主线程任务,并行减少时间

异步优化痛点
  1. 代码不优雅
  2. 场景不好处理(依赖关系)
  3. 维护成本高
启动器核心思想

充分利用CPU多核,自动梳理任务顺序

  1. 任务Task 化,启动逻辑抽象为Task
  2. 根据所有任务依赖关系排序生成一个有向无环图
  3. 多线程按照排序后的优先级依次执行
更优秀的延迟初始化方案-分批初始化
  1. 利用IdleHandler特性,空闲执行
启动优化其他方案
  1. 提前异步SharedPreferences,在MutilDex前
  2. 启动阶段不使用子进程
  3. 提前异步类加载(mutilDex install 之后直接开启线程,通过class.forName或者new Class)

你可能感兴趣的:(性能优化)