Android 项目优化(应用启动优化)

寸阳分阴须爱惜,休负春色与时光。这篇文章主要讲述Android 项目优化:应用启动优化相关的知识,希望能为你提供帮助。
介绍了前面的优化的方案后,这里我们在针对应用的启动优化做一下讲解和说明。
一、App启动概述一个应用App的启动速度能够影响用户的首次体验,启动速度较慢(感官上)的应用可能导致用户再次开启App的意图下降,或者卸载放弃该应用程序。
应用程序启动有主要分为三种状态,每种状态都会影响应用程序对用户可见所需的时间:冷启动,热启动、温启动。

  • 冷启动:app没有启动过或者进程被杀死,系统不存在该app进程,此时启动为冷启动。冷启动流程就是app启动流程全过程,包括创建app进程、加载资源、启动MainThread、初始化SplashActivity并加载布局等。
  • 热启动:app暂时退到了后台,热启动将它从后台重新带到前台,展示给客户。
  • 温启动:用户点击了back键退出app,又重新启动,不过Application仍在内存中存在,对应的进程并没有被杀掉,不包含Application创建过程。热启动时间指在Application仍然存在的情况下,从用户点击桌面图标,到首页内容全部展示出来。
注:冷启动、热启动、温启动这些状态并不是官方的定义,而是我们基于用户的角度考虑的定义,有的将热启动和温启动统称为热启动。
App启动优化,我们一般指的是,针对冷启动进行优化,这样做也可以在一定程度上改善热启动的性能。
二、App冷启动视觉效果优化我们知道冷启动的阶段执行的操作为:1). 加载并启动应用程序    2).启动后立即显示应用程序空白的启动窗口    3).创建应用程序进程    4).加载闪屏页面
冷启动的视觉效果优化,就是加快闪屏页内容的显示速度,这里我们在Android 项目优化(二):启动页面优化进行了说明,这里就不多赘述了。
三、App 启动耗时统计 1.  Traceview 统计
TraceView的使用方式为,在代码中添加如下:
Debug.startMethodTracing("***") Debug.stopMethodTracing()

运行之后可以在目录下生成文件:内部存储/android/data/${application}/files/***.trace,此文件可以使用Android Studio Profile打开。 打开后的内容如下图所示:
Android 项目优化(应用启动优化)

文章图片
这里我们分析一下Trace文件:
Wall Clock time 是线程真正执行的时间,比如我们测试一个方法执行了100ms,从Wall Clock time上看就是100ms。
Thread time  是指CPU执行的时间,时间只会比Wall Clock Time少,使用Thread Time可以让您更好地了解线程的实际 CPU 使用率中有多少是给定方法或函数消耗的。还可以在方法上右键点击jump to source。实际优化过程中重点关注的就是Thread time。因为发生了死锁,整个wall clock time的时间是很长的,但是Thread time时间反应出来的才是真实在方法上所消耗的时间。Threads(n) 表示的是线程的总数,trace可以查看每个线程,main是我们的主线程,我们可以点任意一个线程查看做了什么。
Call Chart  的最上面表示总时间,垂直向下依次为被调用方法的时间。其中,对于系统Api显示的是黄色,被应用调用的方法是绿色的,第三方api(java sdk也属于第三方)的颜色就是蓝色。
Flame Chart 主要的作用是收集调用方法的时间,比如多次调用LayoutInflate.inflate,Flame Chart会把他们都收集到一起。
Top Down 就是函数的调用列表,可以依次从上往下查看调用列表。Total显示的是总调用时间,self显示的是自身执行的时间,children显示的是子方法被调用的时间。
Bottom Up 和Top Down是相反的,可以依次从下往上查看调用方。
Traceview有以下几点需要注意:
1).Traceview仅用于开发环境,生产环境下不要设置。Traceview 在运行时开销很大,会使得整体运行变慢,因为trace会收集程序运行时所有方法的耗时情况,因此会拖累整体速度。
2).我们可以通过TraceView+Cpu Profile进行结合使用,使用TraceView埋点,Cpu Profile 进行分析。
2. adb 命令统计
adb命令 :  adb shell am start -S -W 包名/启动类的全限定名  , -S 表示重启当前应用。示例如下:
C:\\Android\\Demo> adb shell am start -S -W com.example.moneyqian.demo/com.example.moneyqian.demo.MainActivity Stopping: com.example.moneyqian.demo Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.example.moneyqian.demo/.MainActivity } Status: ok Activity: com.example.moneyqian.demo/.MainActivity ThisTime: 2247 TotalTime: 2247 WaitTime: 2278 Complete

ThisTime : 最后一个 Activity 的启动耗时(例如从 LaunchActivity - > MainActivity「adb命令输入的Activity」 , 只统计 MainActivity 的启动耗时)
TotalTime : 启动一连串的 Activity 总耗时.(有几个Activity 就统计几个)
WaitTime : 应用进程的创建过程 + TotalTime .
总结一下 : 如果需要统计从点击桌面图标到 Activity 启动完毕,可以用WaitTime作为标准,所以优化冷启动我们只要在意  ThisTime  即可,ThisTime的时长可以作为验证我们冷启动优化成果的标志。
3.  系统日志统计
根据系统日志来统计启动耗时,在Android Studio中查找已用时间,必须在logcat视图中禁用过滤器(No Filters)。因为这个是系统的日志输出,而不是应用程序的。
比如我们可以通过过滤displayed输出的启动日志. 示例如下:
Android 项目优化(应用启动优化)

文章图片

这样的方式,不适用于冷启动优化,因为输出的日志与冷启动的关系不大,无参考意义。但是能方便我们快速排查出一些Activity页面的启动时间异常问题并进行优化。
四、冷启动 Application 优化我们知道有很多第三方组件(包括App应用本身)都在 Application 中完成初始化操作。但是在 Application 中完成繁重的初始化操作和复杂的逻辑就会影响到应用的启动性能。
通过分析一下,我们可以知道还是有机会优化这些工作以实现冷启动的性能改进的,分析后发现影响冷启动时间的常见问题如下:
  • 复杂繁琐的布局初始化
  • 阻塞主线程 UI 绘制的操作,如 I/O 读写或者是网络访问.
  • 其它占用主线程的操作
我们可以根据这些组件的轻重缓急之分,对初始化做一下分类 :
  • 必要的组件一定要在主线程中立即初始化(入口 Activity 可能立即会用到)
  • 组件一定要在主线程中初始化,但是可以延迟初始化。
  • 组件可以在子线程中初始化。
在进行优化的时候,需要注意以下几种情况:
  • 放在子线程的组件初始化建议延迟初始化,这样就可以了解是否会对项目造成影响! 
  • 将需要在主线程中初始化但是可以不用立即完成的动作延迟加载(初始化放在 Application 中统一管理为妙,不建议放在Activity里面)
  • 可以尝试将常见的组件库,例如 Bugly,x5内核初始化,SP的读写,友盟等组件放到子线程中初始化。(子线程初始化不能影响到组件的使用)
在优化好启动时间后,我们就可以在针对闪屏页的时间,进行调整优化,具体公式为:闪屏页展示总时间 = 组件初始化时间 + 剩余展示时间。
推荐的优化方案:
1). 合理的使用异步初始化、延迟初始化、懒加载机制。
2). 提前加载SharePreferences,可参考:SharedPreferences异步加载。
3). 类加载优化:提前异步执行类加载。
4). 合理使用IdleHandler进行延迟初始化。
 
参考资料:
1. Android性能优化之启动优化工具(TraceView、Systrace、Profiler)
2.  Android性能优化之CPU Profiler
【Android 项目优化(应用启动优化)】 

    推荐阅读