UI卡顿优化

神奇的16ms

Android 系统每隔 16ms 发出 VSYNC 信号触发对UI进行渲染,那么就要求每一帧都要在 16ms 内绘制完成(包括发送给 GPU 和 CPU 绘制到缓冲区的命令),这样就能够达到流畅的画面所需要的60fps。

image

如果你的某个操作花费时间是24ms,系统在得到 VSYNC 信号的时候就无法进行正常渲染,这样就发生了丢帧现象。那么用户在 32ms 内看到的会是同一帧画面。

image

有很多原因可以导致丢帧(卡顿),这里列举一些常见的:

  • layout 太过复杂,层次过多
  • UI 上有层叠太多的绘制单元,过度绘制
  • CPU 或者 GPU 负载过重
  • 动画执行的次数过多
  • 频繁 GC,主要是内存抖动
  • UI 线程执行耗时操作
  • 等等

layout 太过复杂,层次过多

layout 布局是一棵树,树根是 window 的 decorView,套嵌的子 view 越深,树就越复杂,渲染就越费时间。每个 View 都会经过 measure、layout 和 draw 三个流程,都是从树根开始,那么选父布局的时候就要考虑渲染的性能问题:这里分析一下常用的布局控件 LinearLayout 和 RelativeLayout:

LinearLayout

LinearLayout 在 measure 的时候,在横向或者纵向会去测量子 View 的宽度或高度,且只会测量一次,但是当设置 layout_weight 属性的时候会去测量两次才能获得精确的展示尺寸。

RelativeLayout

RelativeLayout 在 measure 的时候会在横向和纵向各测量一次。

简析

如果带有 weight 属性的 LinearLayout 或者 RelativeLayout 被套嵌使用,measure 所费时间可能会呈指数级增长(两个套嵌的叶子 view 会有四次 measure,三个套嵌的叶子 view 会有8次的 measure)。为了缩短这个时间,保持树形结构尽量扁平(深度低),而且尽量要移除所有不需要渲染的 view。

优化
  • 避免复杂的 View 层级
  • 避免 layout 顶层使用 RelativeLayout
  • 布局层次相同的情况下,使用 LinearLayout
  • 复杂布局建议采用 ConstraintLayout 或 RelativeLayout 而不是多层次的 LinearLayout
  • <include/> 标签复用
  • <merge/> 标签减少嵌套
  • 尽量避免 layout_weight
  • 视图按需加载或者使用 ViewStub

注:不会查看布局层次及时间的请查看上一篇UI检测

层叠太多,过度绘制

跟 measure 一样, View 的绘制也是从树根开始一层一层往叶子绘制,就难免导致叶子的绘制挡住了其父节点的一些绘制的内容。过渡绘制是一个术语,表示某些组件在屏幕上的一个像素点的绘制次数超过 1 次。过度绘制导致的问题是花了太多的时间去绘制那些堆叠在下面的、用户看不到的东西,浪费了 CPU 周期和渲染时间。

如何查看是否过渡绘制
  • 打开手机的开发者选项
  • 找到 调试GPU过度绘制
  • 选择 显示过度绘制区域
image

此时我们可以看到屏幕上"丰富多彩"了。

蓝色,淡绿,淡红,深红代表了4种不同程度的 Overdraw 情况,我们的目标就是尽量减少红色 Overdraw,看到更多的蓝色甚至白色区域。

image
如何优化
  • 去除重复或者不必要的 background
  • 点击态中的 normal 尽量设置成 transparent
  • 去除 window 中的 background(这个可以通过处理 decorView 或者设置 Theme 的方式)
  • 若是自定义控件的话,通过 canvas.clipRect() 帮助系统识别那些可见的区域

负载过重

UI 线程是应用的主线程,很多的性能和卡顿问题是由于在主线程中做了大量的工作。除了主线程外,子线程占用过多 CPU 资源也会导致渲染性能问题。

在 UI 渲染的过程中,是 CPU 和 GPU 共同合作完成的,其中 CPU 负责把 UI 组件计算成 Polygons,Texture 纹理,然后交给 GPU 进行栅格化渲染。

GPU 呈现模式分析

打开方法:

  • 打开手机的开发者选项
  • 找到 GPU呈现模式分析
  • 选择 在屏幕上显示为条形图
image

此时我们可以看到屏幕的上放或下方多了各种颜色的条形图。

各颜色含义:


image
个人简析

GPU呈现模式主要方便看到连续的界面绘制是否超过16ms,不方便看每个界面详细的绘制时间,推荐使用Hierarchy Viewer查看详细的具体是绘制时间。

内存抖动

image

主要导致原因是频繁创建大对象或者频繁创建大量对象,并且这些对象属于用完就废弃的,比如 byte[] 。

优化
  • 大对象可以使用对象池复用,比如 byte[]
  • 尽量在 16ms 内少创建对象,比如在 onDraw 中创建 Paint 对象,decode Bitmap 之类的

硬件加速

并非所有的都支持硬件加速,其中包括 clipPath() 等;同时也有一些方法在开启硬件加速之后与不开启硬件加速效果不一样,比如 drawBitmapMesh() 等。

Application 级别
<applicationandroid:hardwareAccelerated = "true" ...>
Activity 级别
<activity android:hardwareAccelerated = "true" ...>
Window 级别
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
View 级别
View.setLayerType(View.LAYER_TYPE_HARDWARE, null);
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,576评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,515评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,017评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,626评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,625评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,255评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,825评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,729评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,271评论 1 320
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,363评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,498评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,183评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,867评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,338评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,458评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,906评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,507评论 2 359

推荐阅读更多精彩内容