Android UI性能优化原理
Posted wodongx123
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android UI性能优化原理相关的知识,希望对你有一定的参考价值。
UI性能优化原理
1. UI加载和卡顿原理
1.1 XML加载到屏幕的流程
- 我们写完XML文件
- 我们在Activity中调用setContentView()方法,本质上是调用内部phoneWindow中DecorView的LyaoutInflater.inflate方法,加载成布局文件。
- 通过CPU的计算,将布局文件转换成多维图形
- CPU通过OPENGL调用GPU
- GPU加载图形
1.2 FPS和卡顿原理
FPS,frames per second,即每秒传输帧率。
也就是一秒钟内在屏幕上连续投射出的静态画面,每一张静态图片被称为一帧。
对于我们人类来说,FPS10-12以上(也就是在一秒钟内出现10-12张静态画面)时,我们会本能认为他是连贯的。
一般现在的APP其FPS基本都需要有60,如果低于60的时候我们就会感觉到画面的卡顿和迟滞现象。
fps需要60,就意味着1000ms内,需要绘制60张静态画面,也就是16.67ms内,他需要绘制出一张图片,并且准时的投放到屏幕上。
如果我们在绘制某一帧画面时,他的耗时超过了16ms。垂直同步的机制会让显示器等待GPU绘制完成之后,再显示到屏幕上。
这就意味着画面在这一帧上停留了超过16ms,也就意味着FPS会<60,我们自然就会感受到卡顿了。
1.3 16ms内都做了些什么
其实就是做了1.1的内容,但是这里要注意的是
在这个16ms内,CPU和GPU不是并行运行的,而是CPU先将布局文件转成多维图形,然后发给GPU再由GPU去绘制。
2. 过度绘制
GPU的绘制是根据CPU的指令来的,所以CPU让他画什么他就画什么,这会导致有些图像会被其他的图像覆盖,底下的图像先画了一边,上面的图像又画了一遍。但是用户只能看到上面的图像,这就造成了性能的浪费。
- 布局层级太深,用户看不到的区域也被绘制
- 自定义控件中,ondraw方法做了太多的绘制。
2.1 如何查看过度绘制
android系统内置了这个功能,打开设置中的开发者模式,硬件加速渲染的调试GPU过度绘制中选择打开
overdraw的层数越高,就表示在这个区域内GPU绘制的次数就越多,所以我们就需要尽可能的去减少红色的区域,增加蓝色的区域。
3. UI如何优化
于是最终的优化就分为两个方向:CPU减少XML转成对象的时间;GPU减少重复绘制
3.1 CPU减少计算
我们都知道,Android系统中多个不同的ViewGroup类型,有LinearLayout,RelativeLayout等。同一个界面的布局,在不同的编程者手上,很有可能会出现不同的布局方式,有些人会用LinearLayout,有些人会用RelativeLayout。
这里有一个很关键的问题,这些不同的布局,对于CPU来说,他所需要的计算时长是相同的吗?显然不是。
一般情况下,对于表达能力越强的Layout,CPU所需要的计算时间就越长(其实也就是代码的逻辑更复杂),而表达能力较弱的Layout计算时间就更短。比如说LinearLayout只有横向或者纵向的两种布局方式,而RelativeLayout对于每个控件都需要去计算他们的相对位置,这个就很明显计算所需的时间就完全不同。
这样我们就需要尽量去选择合理的布局来减少CPU的计算时间
3.2 GPU减少绘制
- 最经典的例子,ImageView,在设置了backgroud的情况下,又设置了具体的图片,这个就是过渡绘制,遇到这种情况,我们尽量就是使用代码来减少imageView的绘制层数。
- 注意backgroud,我们很经常会在最外层的Layout中设置一个backgroud,然后在内部的layout中又设置一次background,这样也会造成过渡绘制。
- 使用clip方法减少渲染的区域,比如说出现多层次的视图覆盖的情况下,就通过clip方法,让View的被覆盖部分不被绘制,这样就可以减少绘制的层数
- 注意透明度:当我们设置一个图片或者视图的背景为透明时,这种情况是不会出现过渡绘制的,但是如果我们设置透明度这个属性的话(比如说透明50%),是会增加绘制的层数的。这种情况下,就需要我们去具体的抠细节。
- TextView的透明度:TextView需要设置透明度的时候,不要直接调用setAlpha方法,而是调用textColor的setAlpha方法,因为TextView只有字是有颜色的吧,不需要整体都设置透明度,字有透明度就行。
- ImageView的透明度:不要直接调用setAlpha方法,而是调用setImageAlpha方法,因为ImageView只有图片是有颜色的吧,也不需要整体的透明度,图片有透明度就行。
- 自定义View的透明度:也是一样的道理,比起对整个View设置透明度,对paint设置透明度可以合理的减少GPU绘制层数。
3.3 冲突
鱼和熊掌不可兼得,往往我们在减少CPU计算的时候,很有可能就会增加GPU的绘制层数;而减少GPU绘制层数的时候,又会增加CPU的计算时间。
这种情况,就需要我们根据具体的情况去具体分析了,选择一个比较好的解决方案。
- 举例1:
假设我们在ImageView上加载一张图片,但是这个图片他不是初始的矩形,而是一个带圆角的图形,那这种时候怎么办呢。
方法1:通过计算算出实际需要绘制的图片大小,画出一个带圆角的图片(减少绘制层数)
方法2:先画出整个图片,然后在四个圆角处,再画上四个和背景颜色相同的纯图片,盖住这一部分(减少CPU计算)
这就是一个冲突的实例,我们往往只能选择其中一个方法进行优化,这样就需要根据情况去选择实际效率更高的一方,这里选方法2会比较好。 - 举例2:
每个人都一定会遇到的问题
方法1:用两个LinearLayout嵌套
方法2:用RelativeLayout一层解决
参考这篇:Android中RelativeLayout和LinearLayout性能分析 - 简书
https://www.jianshu.com/p/8a7d059da746
总之RelativeLayout会对子View进行两次mreasure,而LinearLayout如果用到了weight时,也会对子View进行两次measure。
如果视图过于简单,比如上图,用哪种影响都不会很大,复杂情况的话就只能根据具体情况去具体分析了,比较考验经验。
4. 内存抖动与UI卡顿的关系
内存抖动,是指在短时间内,有大量的对象被创建或者回收的情况。造成的原因是频繁在循环中创建对象。
因为内存抖动会频繁的触发GC,而GC的时候会stop the world,暂停线程的工作。
当线程因为内存抖动被反复暂停工作的时候,那CPU计算所需要的时间就会变长,自然也会造成UI卡顿。
所以做好内存管理对于UI的流畅度也有帮助。
5. 总结
UI的性能优化都是一些大的方法论,实际上要在项目中操作的时候,肯定是每一个页面每一个控件的去检查是否还有优化的空间。也就是说UI的优化都是从小做起从细节做起的。
参考材料
码牛学院 VIP课程 2020.9.19 Android性能优化-UI优化
(Overdraw)过度绘制什么时候出现,如何查看及如何解决
https://blog.csdn.net/wdx_1136346879/article/details/85778495
Android 高级进阶之overdraw分析及解决_Android Developer的博客-CSDN博客
https://blog.csdn.net/weixin_43901866/article/details/91876216(日期最早2019-6-13,但是图片大多损坏)
https://blog.csdn.net/u013309870/article/details/98662984(图片可显示)
Android性能优化之如何避免Overdraw - 简书
https://www.jianshu.com/p/145fc61011cd
以上是关于Android UI性能优化原理的主要内容,如果未能解决你的问题,请参考以下文章