Android UI性能优化原理

1. UI加载和卡顿原理

1.1 XML加载到屏幕的流程

  1. 我们写完XML文件
  2. 我们在Activity中调用setContentView()方法,本质上是调用内部phoneWindow中DecorView的LyaoutInflater.inflate方法,加载成布局文件。
  3. 通过CPU的计算,将布局文件转换成多维图形
  4. CPU通过OPENGL调用GPU
  5. 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让他画什么他就画什么,这会导致有些图像会被其他的图像覆盖,底下的图像先画了一边,上面的图像又画了一遍。但是用户只能看到上面的图像,这就造成了性能的浪费。

  1. 布局层级太深,用户看不到的区域也被绘制
  2. 自定义控件中,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减少绘制

  1. 最经典的例子,ImageView,在设置了backgroud的情况下,又设置了具体的图片,这个就是过渡绘制,遇到这种情况,我们尽量就是使用代码来减少imageView的绘制层数。
  2. 注意backgroud,我们很经常会在最外层的Layout中设置一个backgroud,然后在内部的layout中又设置一次background,这样也会造成过渡绘制。
  3. 使用clip方法减少渲染的区域,比如说出现多层次的视图覆盖的情况下,就通过clip方法,让View的被覆盖部分不被绘制,这样就可以减少绘制的层数
    在这里插入图片描述
  4. 注意透明度:当我们设置一个图片或者视图的背景为透明时,这种情况是不会出现过渡绘制的,但是如果我们设置透明度这个属性的话(比如说透明50%),是会增加绘制的层数的。这种情况下,就需要我们去具体的抠细节。
    1. TextView的透明度:TextView需要设置透明度的时候,不要直接调用setAlpha方法,而是调用textColor的setAlpha方法,因为TextView只有字是有颜色的吧,不需要整体都设置透明度,字有透明度就行。
    2. ImageView的透明度:不要直接调用setAlpha方法,而是调用setImageAlpha方法,因为ImageView只有图片是有颜色的吧,也不需要整体的透明度,图片有透明度就行。
    3. 自定义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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值