内容的快速加载很重要,渲染的流畅性也很重要。android团队把滞缓,不流畅的动画定义为jank,一般是由于丢帧引起的。安卓设备的屏幕刷新率一般是60帧每秒(1/60fps=16.6ms每帧),所以你想要渲染的内容能在16ms内完成十分关键。每丢一帧,用户就会感觉的动画在跳动,会出现违和感。
定位性能问题,一般需要多个工具配合使用,trace是必不可少的,既可以用DDMS里面的,也可以用Android Device Monitor里面带的(支持分线程统计);再结合DDMS里面的其他工具及开发人员选项里面的工具便可解决问题。
在设置->开发者选项->调试GPU过度绘制->打开显示过度绘制区域后,可以看见如下图(对settings当前界面过度绘制进行分析):
可以发现,开启后在我们想要调试的应用界面中可以看到各种颜色的区域,具体含义如下:
颜色 | 含义 |
---|---|
无色 | 无过度绘制或WebView等的渲染区域 |
蓝色 | 1x过度绘制 |
绿色 | 2x过度绘制 |
淡红色 | 3x过度绘制 |
红色 4x(+) | 过度绘制 |
我们需要依据此颜色分布进行代码优化,多数情况下,大面积的过度绘制一般是由于父布局及上层容器设置了冗余的background导致的。我们可以通过DDMS中的Dump View Hierarchy for UI Automator查看过度绘制区域的层级结构,快速一层层的进行优化,如图:
另外,如果对于代码不熟悉,也可以通过resource-id或者text快速定位到其对应的layout布局文件中;
使用Hierarchy View工具来进行两点优化
A.查找整个view树中的冗余层级,减少层次,优化结构;
B.快速找出性能瓶颈位置(通过分析各view中measure,layout,draw时间比例)
2.2.1 启动Hierarchy View
一种是在Android sdk中,在 tools 目录下面找到hierarchyviewer.bat即可
另外一种从Android Device Monitor中打开,启动 Android Device Monitor 成功之后,在新的窗口中点击切换视图图标,选择 Hierarchy View ,如下图:
2.2.2 load Activity的view树
黑体字就是表示当前界面的Activity,双击就load,等下下就能看见view tree了
Ps:该功能只能用在开发机或者虚拟机上,普通的手机没法用(安全性考虑);第三方虚拟机如bluestack可以使用,速度比较快;Android自带的虚拟机也可以,就是速度比较慢。
上图所示为一个Activity的view tree,右上角窗口是整个树结构的概览图,右下角窗口是整个界面的概览图,中间窗口可以拖拽、缩放,选中某个view后会显示详细信息,右下角窗口标识出对应区域,Tree View窗口底部有搜索功能。
一个界面的层次结构越复杂、层级越深,测量、绘制时所需要的时间就越多;通过查看view tree,可以快速定位冗余层级,减少不必要层次(线性排列的view group能否合并)、合并不必要分割(比如两个兄弟view group能否合并)。
2.2.3 Obtain layout time for tree rooted as selected node
选中一个view后,点击上图中的绿红紫按钮,就会以该view为根节点,测量它所有子view的measure、layout、draw时间。Ps:用第三方的虚拟机,比如bluestack,该功能不好使,可以用Android自带的虚拟机,也不好用的时候,换不同的Android版本试试;
得到下图所示结果:
点击每个view都可以看到具体细节,详细意义如下图:
每个view里红色,黄色和绿色的圆圈,它们表示该view在那一层树形结构里measure,layout和draw所花费的相对时间(从左到右)。绿色表示最快的前50%,黄色表示最慢的前50%,红色表示那一层里面最慢的view。显然,红色的部分是我们优先优化的对象。
静态页面标准:在当前界面中没有动画,没有主动执行的后台操作,界面是静态的,意味着这种情况下是不会有cpu消耗或者极少消耗。
当我们在使用app过程中,需要重点测试有各类动画和后台功能的页面,当该页面切换到静态页面时,该页面可能有两种状态,onStop或者onDestroy了,这时执行静态测试,测试是否有未停止的动画、线程、未remove的handler runnable等;
测试方法1
在开发者选项中,打开显示CPU使用情况开关,如下图
A.在右边会显示当前运行的进程列表,排列顺序是按照CPU占用降序排列,越往上表示消耗CPU越多
B. 绿色表示 userspace占用cpu百分比,红色表示kernel 占用cpu百分比,蓝色表示 io interrupt 占用cpu百分比.
C. 第一行表示所有进程叠加的占用CPU百分比,从左到右三个数表示userspace,kernel,io interrupt
通过观察被测应用进程的cpu使用情况,理论情况下,静态页面中,应用应该不消耗或者消耗极少的cpu,如果应用进程一直排在前面在消耗cpu的情况,说明一直有方法在运行,这时可以使用测试方法2找出哪些方法在后面跑。
测试方法2
使用DDMS中的Traceview进行定位
Traceview工具是一个分析器,记录了应用程序中每个函数的执行时间;
打开DDMS,然后选择一个进程,接着点击上面的“Start Method Profiling”按钮(红色小点变为黑色即开始运行,再次点击后停止)。
有帧动画在运行,如下图,AnimationDrawable是帧动画相关的方法
通过Traceview,可以查找出哪些方法没有正确的停止,避免不必要的cpu消耗,影响性能;
1.从代码层面直接查找Activity初始化时,初始化了哪些方法,依次估算这些方法的性能消耗,尽可能的不要在主线程中执行耗时操作,影响界面刷新造成卡顿;
2.使用Traceview进行定位
启动应用或者页面时同时开始Trace采集,可以看到所有方法消耗cpu的百分比及排序,将方法依次对应回代码中,特别是观察运行在main线程的方法有没有优化空间;
3.不必须模块使用时加载
不必要的模块或者不必要的方法,延时加载或者使用时动态加载。比如drawerlayout的侧边栏,FrameLayout中的多个层,可以使用时再加载;Viewpager的多个页面平衡什么时候加载;
A. 使用GPU呈现模式图考核UI性能
通过开发者选项中GPU呈现模式图工具来进行流畅度考量的流程是(注意:如果是在开启应用后才开启此功能,记得先把应用结束后重新启动)在设置->开发者选项->GPU呈现模式(不同设备可能位置或者叫法不同)中打开调试后可以看见如下图(对settings当前界面上下滑动列表后的图表):
打开上图可视化工具后,我们可以在手机画面上看到丰富的GPU绘制图形信息,分别展示了StatusBar、Activity区域等的GPU渲染时间信息,随着界面的刷新,界面上会以实时柱状图来显示每帧的渲染时间,柱状图越高表示渲染时间越长,每个柱状图偏上都有一根代表16ms基准的绿色横线,每一条竖着的柱状线都包含三部分(蓝色代表测量绘制Display List的时间,prepare(紫色),红色代表OpenGL渲染Display List所需要的时间,黄色代表CPU等待GPU处理的时间),只要我们每一帧的总时间低于基准线就不会发生UI卡顿问题(个别超出基准线其实也不算啥问题的)。
可以发现,这个工具是有局限性的,他虽然能够看出来有帧耗时超过基准线导致了丢帧卡顿,但却分析不到造成丢帧的具体原因。所以说为了配合解决分析UI丢帧卡顿问题我们还需要借助traceview和systrace来进行原因追踪。
B. 使用Systrace进行分析优化
打开DDMS->Capture system wide trace using Android systrace->设置时间与选项点击OK就开始了抓取,接着操作APP,完事生成一个trace.html文件,用Chrome打开即可如下图:
界面很复杂,涉及的东西比较多,要想完全弄明白需要扎实的Android基础;
主要看两个地方,一个是如图带有警示标示的圆圈,这些都是有问题的地方,点击小圆圈在左下方会有详细说明
另外一个地方看,带有F标记的小圆圈
每个F标记表示一帧,原点不是绿色的基本都代表存在一定问题,点击后下面会提示你选择的帧相关详细信息或者alert信息,但是遗憾的是通过Systrace只能大体上发现是否存在性能问题,具体问题还需要通过Traceview或者代码中嵌入Trace工具类等去继续详细分析;
BlockCanary对主线程操作进行了完全透明的监控,并能输出有效的信息,帮助开发分析、定位到问题所在,迅速优化应用。其特点有:
非侵入式,简单的两行就打开监控,不需要到处打点,破坏代码优雅性。
精准,输出的信息可以帮助定位到问题所在(精确到行),不需要像Logcat一样,慢慢去找。
目前包括了核心监控输出文件,以及UI显示卡顿信息功能。
具体原理参见git地址:https://github.com/markzhai/AndroidPerformanceMonitor
可以设置debug模式下弹通知栏,方便定位问题
~~待续