保证应用流畅度,是指保证应用在使用过程中能持续提供每秒60帧的运行态。如果低于60帧每秒,就会出现视觉上的卡顿效果(掉帧,也称Jank)。开发应用功能容易,但是保证流畅程度仍是不小的挑战。这里我利用systrace监测应用各组件随着时间的运行状态,分析并着手解决卡顿问题。
SysTrace
这是Android 4.1及之后推出的系统性能检测工具,它在SDK包的platform-tools/systrace文件夹下。保持ADB连接的情况下,我们利用Terminal打开systrace.py并生成分析数据。
如何生成
环境为Mac,配置了adb,python。
1)保持ADB device的连接;
2)cd 到systrace的目录下:如cd Android/sdk/platform-tools/systrace;
- 比如我想测试退出登录到重新登录的性能情况,执行:
python systrace.py --time=10 -o mytrace.html sched gfx view wm
时间默认是5秒,mytrace.html
即我生成的检测结果,在systrace中找到并用chrome打开(注意python使用2.x版本)。
此时控制台中会有以下显示:
在捕获过程中就可以执行退出登录的操作。10s后(自定义的时间)完成捕获,生成数据。
图形界面
我们在之前完成了数据捕获后,在Chrome中打开HTML可以看到类似一下内容:
这里我们可以看到在trace过程中,不少进程都在同时执行任务,红框部分即我要关注的项目。整个图横坐标以时间(ms)为单位,纵轴以进程或者线程为单位。
红框部分的绿,黄,红圆圈分别表示Frame行在绘制时的性能状态。正常情况以绿色的圆点表示。当圆点颜色为黄色或者红色时,意味着这一帧超过16.6ms(即发现丢帧),这时需要通过放大那一帧进一步分析问题。
点击右上角的问号可以查看一些快捷键:
项目优化
上图即项目生成的性能状态图。我们点击一下红色的代表着丢帧严重的圆圈:
发现底部Frame一栏弹出警示信息:"Scheduling delay"。Scheduling delay(调度延迟)的意思就是一个线程在处理一块运算的时候,在很长一段时间都没有被分配到CPU上面做运算,从而导致这个线程在很长一段时间都没有完成工作。我们发现这帧只运行了1.6ms,而有100多ms是在休眠,这意味着这一帧的渲染过程非常慢。
我们通过'w'快捷键放大UI Thread,点击一下时序图:
这里可以看到UI线程在执行perform Traversals
。遍历?这是在进行什么操作呢?
我们放大红色圆圈后面那个黄色圆圈的时序图,可以看到:
UI在执行了一个长perform Traversals
后,开始了layout和draw的绘制。到这里我们回想一下,我们想要检测的内容是:退出登录到重新登录的界面UI状态,于是我们可以推测,这应该是点击了退出登录以后经历了的一个操作。
我们还需要证实一下,查看点击退出以后,各方法执行的时间。于是打开DDMS的traceView,采集退出登录那一段时间的状态:
这里列出一个 Profile Panel(分析面板)各时间的含义:
我们以RealTime/Call时间做一下降序,发现Main方法做了大量耗时操作!
检查退出登录以后的代码,发现了问题所在:点击了退出后,我们直接将当前Activity退栈,由升至栈顶的MainActivity做登录态检测,如果发现用户此时已经退出了登录,则跳转至登录页面。
但同时执行了onResume()操作以后,UI又将会使用大量时间将MainActivity绘制一遍!
我们修改了相关逻辑以后,再重新使用systrace查看一下效果:
好了不少!说明修改有效,我们接着分析后面的丢帧行为。
发现Alert提示"Expensive measure/layout pass"。我点击了随后的几个报警圆圈,发现都是和View的绘制有关,那么问题就应该是登录界面的布局了。
大体的UI卡顿原因为:
布局Layout过于复杂,无法在16ms内完成渲染;
同一时间动画执行的次数过多,导致CPU或GPU负载过重;
View过度绘制,导致某些像素在同一帧时间内被绘制多次,从而使CPU或GPU负载过重;
View频繁的触发measure、layout,导致measure、layout累计耗时过多及整个View频繁的重新渲染;
内存频繁触发GC过多(同一帧中频繁创建内存),导致暂时阻塞渲染操作;
冗余资源及逻辑等导致加载和执行缓慢;
我们重新设计登录页面的布局,减少View的重叠和嵌用,再次测试的时候,不用生成systrace,在低配机上调试就能明显感觉到UI的体验性在改善!
当然,布局的优化远不是一两行话就能解决的,我也在慢慢学习,完善用户体验,这才是开始!