本文参考了
hyczlf(https://blog.****.net/LF_HYCZ/article/details/76034457)
joye123(https://blog.****.net/joye123/article/details/79425398)
jeanboydev(https://blog.****.net/freekiteyu/article/details/77862670)
等文章,如若侵权,请联系删除。
在我们开发使用的APP中经常会看到程序动画卡顿的现象,
Android 应用的卡顿,丢帧等,这些影响用户体验的因素绝大部分都与 16ms 这个值有关。 下面我们来讨论下 UI 渲染方面影响应用流畅性的因素。
16ms
- 12 fps(帧/秒):由于人类眼睛的特殊生理结构,如果所看画面之帧率高于每秒约 10-12 fps 的时候,就会认为是连贯的。
早期的无声电影的帧率介于 16-24 fps 之间,虽然帧率足以让人感觉到运动,但往往被认为是在快放幻灯片。
在1920年代中后期,无声电影的帧率提高到 20-26 fps 之间。 - 24 fps:1926 年有声电影推出,人耳对音频的变化更敏感,反而削弱了人对电影帧率的关注。因为许多无声电影使用 20-26 fps
播放,所以选择了中间值 24 fps 作为有声电影的帧率。 之后 24 fps 成为35mm有声电影的标准。 - 30 fps:早期的高动态电子游戏,帧率少于每秒 30 fps 的话就会显得不连贯。这是因为没有动态模糊使流畅度降低。
(注:如果需要了解动态模糊技术相关知识,可以查阅 这里) - 60 fps:在实际体验中,60 fps 相对于30 fps 有着更好的体验。
- 85 fps:一般而言,大脑处理视频的极限。
所以,总体而言,帧率越高体验越好。 一般的电影拍摄及播放帧率均为每秒 24 帧,但是据称《霍比特人:意外旅程》是第一部以每秒 48 帧拍摄及播放的电影,观众认为其逼真度得到了显著的提示。
目前,大多数显示器根据其设定按 30Hz、 60Hz、 120Hz 或者 144Hz 的频率进行刷新。 而其中最常见的刷新频率是 60Hz。 这样做是为了继承以前电视机刷新频率为 60Hz 的设定。 而 60Hz 是美国交流电的频率,电视机如果匹配交流电的刷新频率就可以有效的预防屏幕中出现滚动条,即互调失真。
正如上面所述目前大多数显示器的刷新率是 60Hz,Android 设备的刷新率也是 60Hz。只有当画面达到 60fps 时 App 应用才不会让用户感觉到卡顿。那么 60fps 也就意味着 1000ms/60Hz = 16ms。也就是说 16ms 渲染一次画面才不会卡顿。
知道了上面的知识,那么我来总结一下Ui卡顿的原因以及解决方案。
UI卡顿的根本原因
通过上述的结论我们知道,如果由于一些原因导致了我们的逻辑、CPU耗时、GPU耗时大于16ms,UI就无法完成一次绘制,那么就会造成卡顿。简单的一句话就是:卡主线程了。
比如说,在16ms内,发生了频繁的GC:
然而追其应用层的话,就是常见View的内存抖动问题以及主线程太耗时(CPU占用)两个原因。
内存抖动
常见的内存抖动的原因是就UI中View的绘制过程中创建了大量对象,又大量回收,导致频繁的发生GC,所以会出现Ui卡顿。解决方案就是减少对象的创建以及页面的频繁刷新。
解决实例:使用String的时候将其改为StringBudiler来避免内存频繁创建,TextView和ImageView的组合可以用TextView的setLeftDrawable或者setRightDrawable来添加图片。使用weakRefrence弱引用来创建图片对象。
注意,GC是无法避免的,我们要避免的是频繁的GC,因此这里的优化实质上是内存优化。
方法耗时(CPU占用)
当在主线程绘制过程中出现大量占用CPU的耗时操作时,也会出现Ui卡顿。解决方案就是更换方式使方法不耗时。
原因实例:
1.Json数据解析耗时(Cache类)
2.文件操作(获取所属渠道名称)
3.Binder通信(获取系统属性(mac地址))
4.正则匹配(Hybird 通信)
5.相机操作:初始化、预览、停止预览、释放(反扫)
6.组件初始化(推送)
7.循环删除、创建View(更多页面)
8.WebView首次初始化
解决实例:修复优先级顺序:异步 > 缓存 > 替代方案 > 保持原状。
接下来说说View绘制的内部问题。
比如说过度绘制,如果绘制的层数过高,导致主线程在16ms中无法将整个页面绘制完成就会出现掉帧的情况,从而导致Ui卡顿。
过度绘制
我们的Android手机能过通过:开发者选项 -> 调试GPU过度绘制,来打开该功能,来查看是否出现了过度绘制。
原色:没有过度绘制
蓝色:过度绘制1次
绿色:过度绘制2次
粉色:过度绘制3次
红色:过度绘制4次或更多
请注意,这些颜色是半透明的,因此,您在屏幕上看到的确切颜色取决于您的界面内容。
可以通过此功能查看哪些页面的布局层级过深。
处理方案也有很多种:
去除不必要的背景色
1.设置窗口背景色为通用背景色,去除根布局背景色。
2.若页面背景色与通用背景色不一致,在页面渲染完成后移除窗口背景色
3.去除和列表背景色相同的Item背景色
布局视图树扁平化
1.移除嵌套布局
2.使用merge、include标签
3.使用性能消耗更小布局(TableLayout、ConstraintLayout)
减少透明色,即alpha属性的使用
1.通过使用半透明颜色值(#77000000)代替
其他
1.使用ViewStub标签,延迟加载不必要的视图
2.使用AsyncLayoutInflater异步解析视图
我们常见的Ui卡顿其实在很多情况下是无法发现原因的。所以为了快速找到卡顿原因,就要利用检测工具。
常见的检测工具有:
1.Hierarchy Viewer(分析Ui性能)
2.手机开发者自带GPU呈现模式(考核Ui性能)
3.TraceView (代码层面分析性能问题)
生成 trace 文件有三种方法:
- 使用代码
- 使用 Android Studio
- 使用 DDMS
4.Systrace (检测 App 的性能)
具体的使用方法我来贴一个门,有意者查看原博来看。
Android-性能优化-UI优化