天天看点

Android性能优化——UI卡顿优化

文章目录

    • GPU和CPU
      • 简单介绍
      • 工作流程
      • 刷新频率和卡顿分析
    • GPU过度绘制优化
      • 过度绘制查看工具
      • 优化方案
    • 布局的优化(CPU)
      • 常用工具
      • 注意点

GPU和CPU

简单介绍

​ CPU 的任务繁多,做逻辑计算外,还要做内存管理、显示操作,因此在实际运算的时候性能会大打折扣,在没有 GPU 的时代,不能显示复杂的图形,其运算速度远跟不上今天复杂三维游戏的要求。即使 CPU的工作频率超过 2GHz 或更高,对它绘制图形提高也不大。这时 GPU的设计就出来了

CPU的主要工作是计算,将计算结果丢给GPU进行渲染

Android性能优化——UI卡顿优化

CPU和GPU的结构图如下所示

Android性能优化——UI卡顿优化

黄色的 Control 为控制器,用于协调控制整个 CPU 的运行,包括取出指令、控制其他模块的运行等;

绿色的 ALU ( Arithmetic Logic Unit )是算术逻辑单元,用于进行数学、逻辑运算;

橙色的 Cache 和 DRAM 分别为缓存和 RAM ,用于存储信息。

从结构图可以看出, CPU 的控制器较为复杂,而 ALU 数量较少。因此 CPU 擅长各种复杂的逻辑运算,但不擅长数学尤其是浮点运算。

工作流程

简单介绍一个控件显示到界面上需要经过的步骤

xml文件

通过LayoutInflater解析成对象加载到内存

CPU处理成多维向量图像

CPU 将向量图像交给 GPU,GPU 进行栅格化,然后绘制,负责像素填充。

Android性能优化——UI卡顿优化

UI对象

—-> CPU处理为多维图形,纹理

—–> 通过OpeGL ES接口调用GPU

—-> GPU对图进行光栅化(Frame Rate )

—-> 硬件时钟(Refresh Rate)

—-> 垂直同步

—-> 投射到屏幕

流程的图片流程

Android性能优化——UI卡顿优化

刷新频率和卡顿分析

60Hz 刷新频率由来

12 fps :由于人类眼睛的特殊生理结构,如果所看画面之帧率高于每秒约 10-12 帧的时候,就会
认为是连贯的
24 fps :有声电影的拍摄及播放帧率均为每秒 24 帧,对一般人而言已算可接受
30 fps :早期的高动态电子游戏,帧率少于每秒 30 帧的话就会显得不连贯,这是因为没有动态模
糊使流畅度降低
60 fps 在与手机交互过程中,如触摸和反馈 60 帧以下人是能感觉出来的。 60 帧以上不能察觉
变化
当帧率低于 60 fps 时感觉的画面的卡顿和迟滞现象
           

Android系统每隔16ms发出VSYNC信号(1000ms/60=16.66ms),触发对UI进行渲染, 如果每次渲染都成功,这样就能够达到流畅的画面所需要的60fps,为了能够实现60fps,这意味着计算渲染的大多数操作都必须在16ms内完成。

Android性能优化——UI卡顿优化

当这一帧画面渲染时间超过16ms的时候,垂直同步机制会让显示器硬件 等待GPU完成栅格化渲染操作,

这样会让这一帧画面,多停留了16ms,甚至更多.这样就这造成了 用户看起来 画面停顿.

Android性能优化——UI卡顿优化

当GPU渲染速度过慢,就会导致如下情况,某些帧显示的画面内容就会与上一帧的画面相同

16 毫秒的时间主要被两件事情所占用

第一件:将 UI 对象转换为一系列多边形和纹理( 1 )(?)

第二件: CPU 传递处理数据到 GPU 。所以很明显,我们要缩短这两部分的时间,也就是说需要尽量减少对象转换的次数,以及上传数据的次数 (? 布局 自定义)

如何减少这两部分的时间 以至于在 16ms 完成呢

  1. CPU 减少 xml 转换成对象的时间
  2. GPU 减少重复绘制的时间

GPU过度绘制优化

GPU的绘制过程,就跟刷墙一样,一层层的进行,16ms刷一次.这样就会造成,图层覆盖的现象,即无用的图层还被绘制在底层,造成不必要的浪费.

Android性能优化——UI卡顿优化

GPU过度绘制的几种情况

  1. 自定义控件中,onDraw方法做了过多重复绘制
  2. 布局层次太深,重叠性太强,用户看不到的区域GPU也会渲染,导致耗时增加

过度绘制查看工具

Android性能优化——UI卡顿优化

那 Android 系统有没有给我们做优化的操作呢?

​ CPU 转移到 GPU 是一件很麻烦的事情,所幸的是 OpenGL ES 可以把那些需要渲染的纹理 Hold 在 GPU Memory 里面,在下次需要渲染的时候直接进行操作。所以如果你更新了 GPU 所 hold 住的纹理内容,那么之前保存的状态就丢失了。

​ 在 Android 里面那些由主题所提供的资源,例如 Bitmaps , Drawables 都是一起打包到统一的 Texture 纹理当中,然后再传递到 GPU 里面,这意味着每次你需要使用这些资源的时候,都是直接从纹理里面进行获取渲染的。当然随着 UI 组件的越来越丰富,有了更多演变的形态。例如显示图片的时候,需要先经过 CPU 的计算加载到内存中,然后传递给 GPU 进行渲染。

​ 文字的显示比较复杂,需要先经过 CPU 换算成纹理,然后交给 GPU 进行渲染,返回到 CPU 绘制单个字符的时候,再重新引用经过 GPU 渲染的内容。动画则存在一个更加复杂的操作流程。为了能够使得 App 流畅,我们需要在每帧 16ms 以内处理完所有的 CPU 与 GPU 的计算,绘制,渲染等等操作。

优化方案

  1. 减少背景重复

    主题中的设置

    • 去掉单个activity的主题设置的属性,可以在setContentView之前调用getWindow().setBackgroundDrawable(null);
    • 去掉所有activity主题设置中的属性直接在styles.xml中设置@null
  2. 使用裁减减少控件之间的重合部分

    Android7.0之后系统做出的优化:invalidate()不再执行测量和布局动作

  3. 非业务需要,不要去设置背景

布局的优化(CPU)

常用工具

  1. Android/sdk/tools/bin/ui automator viewer.bat
  2. Android\sdk\tools\monitor.bat
  3. Device Monitor窗口中Hierarchy view

    我们可以借助一些工具来查看我们的布局层级。现在 Hierarchy Viewer 在 SDK 里找不到了,google 已经把它隐藏起来。并且 Hierarchy Viewer 只能在开发版手机或模拟器运行的限制。

Android性能优化——UI卡顿优化
  1. Layout Inspector

    现在 Android Studio 已经不支持 Hierarchy Viewer,也可以使用 Layout Inspector 进行替代查看布局

Android性能优化——UI卡顿优化

注意点

1.能在一个平面显示的内容,尽量只用一个容器

2.尽可能把相同的容器合并merge

3.能复用的代码,用include处理,可以减少GPU重复工作

继续阅读