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打开。
打开后的内容如下图所示:

这里我们分析一下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输出的启动日志. 示例如下:

这样的方式,不适用于冷启动优化,因为输出的日志与冷启动的关系不大,无参考意义。但是能方便我们快速排查出一些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

 

posted @ 2019-10-31 11:45  灰色飘零  阅读(3400)  评论(0编辑  收藏  举报