Android性能优化分为很多种,比较常用的有绘制优化、内存优化、耗电优化和稳定性优化等,这个系列我们就来学习性能优化中的绘制优化。
Android绘制View有三个主要的步骤,分别是measure、layout和draw。measure、layout和draw方法主要是运行在系统的应用框架层,而真正将数据渲染到屏幕上的则是系统Nativie层的SurfaceFlinger服务来完成的。
绘制过程主要是由CPU 来进行Measure、Layout、Record、Execute的数据计算工作,GPU负责栅格化、渲染。CPU和GPU是通过图形驱动层来进行连接的。图形驱动层维护了一个队列,CPU将display list添加到该队列中,这样GPU就可以从这个队列中取出数据进行绘制。
1.1 渲染时间线
FPS(Frames Per Second)它是指画面每秒传输帧数,通俗来讲就是指动画或视频的画面数,最简单的举例就是我们玩游戏时,如果画面在60fps则不会感觉到卡顿,如果低于60fps,比如50fps则会感觉到卡顿,你就可以考虑要换显卡或者采取其他一些措施了。
要想画面保持在60fps,则需要每个绘制时长在16ms以内,如下图所示。
Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染, 如果每次渲染都成功,这样就能够达到流畅的画面所需要的60fps,那什么是VSYNC呢?VSYNC是Vertical Synchronization(垂直同步)的缩写,是一种定时中断,一旦收到VSYNC信号,CPU就开始处理各帧数据。
如果某个操作要花费24ms,这样系统在得到VSYNC信号时无法进行正常的渲染,会发生丢帧。用户会在32ms中看到同一帧的画面,如下图所示。
产生卡顿原因有很多,主要有以下几点:
为了解决上述的问题,除了我们要在写代码时要注意外,也可以借助一些工具来分析和解决卡顿问题。
Profile GPU Rendering是Android 4.1系统提供的开发辅助功能,我们可以在开发者选项中打开这一功能,如下图所示。
打开Profile GPU Rendering_副本_副本.png
我们点击Profile GPU Rendering选项并选择On screen as bars即开启Profile GPU Rendering功能。接着屏幕会显示出彩色的柱状图,如下所示。
Screenshot_20170308-152841_副本.png
上面的彩色的图的横轴代表时间,纵轴表示某一帧的耗时。绿色的横线为警戒线,超过这条线则意味着时长超过了16m,尽量要保证垂直的彩色柱状图保持在绿线下面。这些垂直的彩色柱状图代表着一帧,不同颜色的彩色柱状图代表不同的含义:
在Android 6.0中,有更多的颜色被加了进来,如下图所示:
Profile GPU Rendering可以找到渲染有问题的界面,但是想要修复的话,只依赖Profile GPU Rendering是不够的,可以用另一个工具Hierarchy Viewer来查看布局层次和每个View所花的时间
Systrace是Android4.1中新增的性能数据采样和分析工具。它可帮助开发者收集Android关键子系统(SurfaceFlinger、WindowManagerService等Framework部分关键模块、服务,View体系系统等)的运行信息。Systrace的功能包括跟踪系统的I/O操作、内核工作队列、CPU负载以及Android各个子系统的运行状况等。对于UI显示性能,比如动画播放不流畅、渲染卡顿等问题提供了分析数据。
3.1 使用Systrace
Systrace跟踪的设备要在Android4.1版本以上,对于Android4.3版本之前和4.3版本之后使用上有点区别,现在也很少有人用Android4.3之前的版本,因此这里只讲Android4.3版本的使用方法。Systrace可以在DDMS上使用,可以使用命令行来使用,也可以在代码中进行跟踪。接下来分别来介绍这三种方式。
在DDMS中使用Systrace
1.首先我们要打开Android Studio的Tool中的Android Device Monitor,并连接手机。
2.点击Systrace按钮进入抓取设置界面,如下图所示。
抓取设置界面可以设置跟踪的时间,以及trace文件输出的地址等内容。如下图所示。
3.设置完成后,我们就来操作的跟踪的过程。跟踪时间结束后,生成trace.html文件。
4.用Chrome打开trace.html文件进行分析。分析的方法,后文会讲到。
用命令行使用Systrace
Android 提供一个python脚本文件 systrace.py,它位于Android SDK 目录 /tools/systrace 中,我们可以执行以下命令来使用Systrace:
|
在代码中使用Systrace
Systrace并不会追踪应用的所有工作,在Android4.3及以上版本的代码中,可以使用Trace类对应用中的具体活动进行追踪。
Android源码中也引用了Trace类,比如RecyclerView:
|
TraceCompat类对Trace类进行了封装,只会在Android4.3及以上版本才会使用Trace类,其中beginSection方法和endSection方法之间的代码会被追踪,endSection方法会只会结束最近的beginSection方法,因此要保证beginSection方法和endSection方法的调用次数要相同。
3.2 用Chrome分析Systrace
通过前面的方法生成的trace.html需要用Chrome打开,打开后效果如下图所示。
我们可以使用W键和S键进行放大和缩小,A键和D键进行左右移动。
Alert区域
首先来看Alert区域,这一区域会标记处性能有问题的点,单击叹号图标就可以查看某一个Alert的问题描述,如下所示。
这个Alert指出了View在Measure/Layout时耗费了大量的时间,导致出现jank(同一帧画了多次)。给出的建议是避免在动画播放期间控制布局。
CPU区域
接下来我们来查看CPU区域,每一行代表一个CPU核心和它执行任务的时间片,放大后会看到每个色块代表一个执行的进程,色块的长度代表其执行时间,如下图所示。
图中CPU 0主要执行adbb线程和InputReader线程,CPU 2主要执行了surfaceflinger线程和ordinatorlayout进程中的RenderThread线程,我们点击RenderThread色块,会给出RenderThread的相关信息,如下图所示。
图中给出了当前色块所运行的线程和进程、开启时间和持续时间等信息。
应用区域
应用区域会显示应用的帧数,如下图所示。
Systrace会给出应用中的Frames分析,每一帧就是一个F圆圈,F圆圈有三种颜色,其中绿色表示Frame渲染流畅,黄色和红色则代表渲染时间超过了16.6ms,其中红的更严重些。我们点击红色F圆圈,会给出该Frame的信息,如下图所示。
从图中可以看出,Frame给出了问题提示:Scheduling delay(调度延迟),当一帧绘制时间超过19ms会触发该提示,更何况这一帧已经有将近40ms了。导致这一问题产生的原因主要是线程在绘制时,在很长一段时间都没有分配到CPU时间片,因此无法继续进行绘制。按m键来高亮该时间段,我们来查看CPU的情况,如下图所示。
可以看出这个时间段中两个CPU都在满负荷运行。至于具体是什么让CPU繁忙,则需要使用Traceview来进行分析。
Alerts总体分析
点开最右边的Alerts按钮会给出Alert的总体分析,如下图所示。
QQ截图20170312150637.png
Alerts会给出Alert类型,以及出现的次数。有了这些总体的分析,方便开发者对该时间段的绘制性能有一个整体的大概了解,便于进行下一步分析。
由于Systrace 是以系统的角度返回一些信息,只能为我们提供一个概览,它的深度是有限的,我们可以用它来进行粗略的检查,以便了解大概的情况,但是如果要分析更详细的,比如要找到是什么让CPU繁忙,某些方法的调用次数等,则还要借助另一个工具:Traceview。
4.1 使用Traceview
要分析Traceview,则首先要得到一个trace文件,trace文件的获取有两种方式,分别是在DDMS中使用和在代码中加入调试语句,下面分别对这两种方式进行介绍。
DDMS中使用
1.首先我们要打开Android Studio的Tool中的Android Device Monitor,并连接手机。
2.选择相应的进程,并单击Start Method Profiling按钮。
3.对应用中需要监控的点进行操作。
4.单击Stop Method Profiling按钮,会自动跳到TraceView视图。
代码中加入调试语句
如果开发中出现不好复现的问题,则需要在代码中添加TraceView监控语句,代码如下所示。
|
在开始监控的地方调用startMethodTracing方法,在需要结束监控的地方调用stopMethodTracing方法。系统会在SD卡中生成trace文件,将trace文件导出并用SDK中的Traceview打开即可。当然不要忘了在manifest中加入
权限。
4.2 分析Traceview
为了分析Traceview,我们来举一个简单的例子来生成trace文件,这里采用第二种方式:代码中加入调试语句。代码如下所示。
|
在注释1处调用了startMethodTracing方法开始监控,其中test是生成的trace文件的名称。在initView中我们特意调用sleep方法来做耗时操作。在onStop方法中我们调用了stopMethodTracing方法结束监控。这时会在SD卡根目录生成test.trace文件,我们将该文件导出到桌面,用Traceview来分析test.trace文件,我们在cmd中执行如下语句。
我们进入traceview所在的目录(直接将traceview.bat拖入到cmd中),并执行上图的traceview语句后会弹出Traceview视图,它分为两部分,分别是时间片面板和分析面板,我们先来看时间片面板,如下图所示。
其中x轴代表时间的消耗,单位为ms,y轴代表各个线程。一般会查看色块的长度,明显比较长的方法重点去关注,具体的分析还得看分析面板,如下图所示。
每一列数据的代表的含义如下表所示。
列名 | 含义 |
---|---|
Name | 该线程运行过程中调用的函数名 |
Incl Cpu Time% | 某个方法包括其内部调用的方法所占用CPU时间百分比 |
Excl Cpu Time% | 某个方法不包括其内部调用的方法所占用CPU时间百分比 |
Incl Real Time% | 某个方法包括其内部调用的方法所占用真实时间百分比 |
Excl Real Time% | 某个方法不包括其内部调用的方法所占用真实时间百分比 |
Calls + Recur Calls / Total | 某个方法次数+递归调用次数 |
Cpu Time / Call | 该方法平均占用CPU时间 |
Cpu Time / Call | 该方法平均占用真实时间 |
Incl Cpu Time | 某个方法包括其内部调用的方法所占用CPU时间 |
Excl Cpu Time | 某个方法不包括其内部调用的方法所占用CPU时间 |
Incl Real Time | 某个方法包括其内部调用的方法所占用真实时间 |
Excl Real Time | 某个方法不包括其内部调用的方法所占用真实时间 |
因为我们用sleep方法来进行耗时操作,所以这里我们可以单击Incl Real Time来进行降序排列。其中有很多系统调用的方法,我们来进行一一过滤。最终我们发现了CoordinatorLayoutActivity的initView方法Incl Real Time的时间为1000.493ms,这显然有问题,如下图所示。
从图中我们可以看出是调用sleep方法导致的耗时。关于Traceview还有很多种分析情况,就需要大家在平时进行积累了。
对于AndroidStudio 3.2以上版本的 DDMS工具找不到的,可以参考这一篇文章添加一个快速启动插件。https://juejin.im/post/5c556ff7f265da2dbe02ba3c
4.3 扩展 使用DDMS分析问题
打开之后的窗口如图:
除了图上大概标注的功能外,详细的功能有:
1.Devices:查看到所有与DDMS连接的模拟器详细信息,以及每个模拟器正在运行的APP进程,每个进程最右边相对应的是与调试器链接的端口。
2.Emulator Control:实现对模拟器的控制,如:接听电话,根据选项模拟各种不同网络情况,模拟短信发送及虚拟地址坐标用于测试GPS功能等。
3.LogCat :查看日志输入信息,可以对日志输入进行Filter过滤一些调试的信息筛选查看等。
4.File Exporler:File Exporler文件浏览器,查看Android模拟器中的文件,可以很方便的导入/出文件。
5.Heap:查看应用中内存使用情况。
6.Dump HPROF file:点击DDMS工具条上面的Dump HPROF文件按钮,选择文件存储位置,然后在运行hprof-conv。可以用MAT分析heap dumps启 动MAT然后加载刚才我们生成的HPROF文件。MAT是一个强大的工具,讲述它所有的特性超出了本文的范围,所以我只想演示一种你可以用来检测 泄露的方法:直方图(Histogram)视图。它显示了一个可以排序的类实例的列表,内容包括:shallow heap(所有实例的内存使用总和),或者retained heap(所有类实例被分配的内存总和,里面也包括他们所有引用的对象)等。
7.Screen captrue:截屏操作
8.Thread:查看进程中线程情况。
9.其它工具。
可能这样说,不太直观,下面我们通过图片,来简单展示几个的使用:
查看进程中的线程:
DDMS中使用
要生成一个时间段的track文件,点击箭头旁边的Start Method Profiling按钮,结束的时候再次点击同一个按钮只不过显示为Stop Method Profiling按钮。.单击Stop Method Profiling按钮,会自动跳到TraceView视图。
查看内存信息:
文件管理,可以对文件进行导入导出,真机很多操作可能需要Root权限才能进行。模拟器的话可以模拟发短信,打电话,定位等:
查看特定页面的展示及布局元素构成:
本文属于总结性的文章,主要资料参考于刘望舒的博客和书籍以及部分内容收集网友内容。