Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Android性能优化(二)之布局优化面面观

Android性能优化(二)之布局优化面面观

作者头像
用户2898788
发布于 2018-08-21 02:07:37
发布于 2018-08-21 02:07:37
1.1K00
代码可运行
举报
文章被收录于专栏:双十二技术哥双十二技术哥
运行总次数:0
代码可运行

一、初识布局优化

通过《Android性能优化(一)之启动加速35%》我们获得了闪电般的App启动速度,那么在应用启动完毕之后,UI布局也会对App的性能产生比较大的影响,如果布局写得糟糕,显而易见App的表现不可能流畅。

那么本文我同样基于实际案例,针对应用的布局进行优化进而提升App性能。

二、60fps VS 16ms

根据Google官方出品的Android性能优化典范,60帧每秒是目前最合适的图像显示速度,事实上绝大多数的Android设备也是按照每秒60帧来刷新的。为了让屏幕的刷新帧率达到60fps,我们需要确保在时间16ms(1000/60Hz)内完成单次刷新的操作(包括measure、layout以及draw),这也是Android系统每隔16ms就会发出一次VSYNC信号触发对UI进行渲染的原因。

如果整个过程在16ms内顺利完成则可以展示出流畅的画面;然而由于任何原因导致接收到VSYNC信号的时候无法完成本次刷新操作,就会产生掉帧的现象,刷新帧率自然也就跟着下降(假定刷新帧率由正常的60fps降到30fps,用户就会明显感知到卡顿)。

作为开发人员,我们的目标只有一个:保证稳定的帧率来避免卡顿。

三、Avoid Overdraw

理论上一个像素每次只绘制一次是最优的,但是由于重叠的布局导致一些像素会被多次绘制,Overdraw由此产生。

我们可以通过调试工具来检测Overdraw:设置——开发者选项——调试GPU过度绘制——显示过度绘制区域。

原色 – 没有过度绘制 – 这部分的像素点只在屏幕上绘制了一次。 蓝色 – 1次过度绘制– 这部分的像素点只在屏幕上绘制了两次。 绿色 – 2次过度绘制 – 这部分的像素点只在屏幕上绘制了三次。 粉色 – 3次过度绘制 – 这部分的像素点只在屏幕上绘制了四次。 红色 – 4次过度绘制 – 这部分的像素点只在屏幕上绘制了五次。

在实际项目中,一般认为蓝色即是可以接受的颜色。

我们来看一个简单却隐藏了很多问题的界面,App的设置界面。在没有优化之前打开Overdraw调试,可以看到界面大多数是严重的红色:见下图。

贴出这个布局的代码(贴出后超过公众号字数限制,可以点击查看原文查看布局代码)。

每一行布局都使用RelativeLayout嵌套来做,而且设置了多重颜色。

分析布局可知:多层布局重复设置了背景色导致Overdraw。 那么我们结合产品的需求(任何不结合具体场景优化都是耍流氓):

  • 去掉每行RelativeLayout的背景色;
  • 去掉每行TextView的背景色;

备注:一个容易忽略的点是我们的Activity使用的Theme可能会默认的加上背景色,不需要的情况下可以去掉。

去掉背景色之后再看一下Overdraw;

对比一下优化后的布局的颜色,可以看出Overdraw降到了可以接受的程度。

备注:有些过度绘制都是不可避免的,需要结合具体的布局场景具体分析。

四、减少嵌套层次及控件个数

  • Android的布局文件的加载是LayoutInflater利用pull解析方式来解析,然后根据节点名通过反射的方式创建出View对象实例;
  • 同时嵌套子View的位置受父View的影响,类如RelativeLayout、LinearLayout等经常需要measure两次才能完成,而嵌套、相互嵌套、深层嵌套等的发生会使measure次数呈指数级增长,所费时间呈线性增长;

由此得到结论:那么随着控件数量越多、布局嵌套层次越深,展开布局花费的时间几乎是线性增长,性能也就越差。

幸运的是,我们有Hierarchy Viewer这个方便可视化的工具,可以得到:树形结构总览、布局view、每一个View(包含子View)绘制所花费的时间及View总个数

备注: Hierarchy Viewer不能连接真机的问题可以通过ViewServer这个库解决;

使用Hierarchy Viewer来看查看一下设置界面,可以从下图中得到设置界面的一些数据及存在的问题:

  • 嵌套共计7层(仅setContentView设置的布局),布局嵌套过深;
  • measure时间1.569ms,layout时间0.120ms,draw时间16.128ms,合计共计耗时17.871ms;
  • 共绘制85个View,5个多余定位,以及若干个无用布局。

优化方案:

  • 将之前使用RelativeLayout来做的可以替换的行换为TextView;
  • 去掉之前多余的无用布局;

现在我们再使用Hierarchy Viewer来检测一下:

优化后: 1. 控件数量从85个减少到26个,减少69%; 2. 绘制时间从17.8ms减少到14.756ms,降低17%;

总结: 1. 同样的UI效果可以使用不同的布局来完成,我们需要考虑使用少的嵌套层次以及控件个数来完成,例如设置界面的普通一行,可以像之前一样使用RelativeLayout嵌套TextView以及ImageView来实现,但是明显只使用TextView来做:嵌套层次、控件个数都更少。 2. 优化过程中使用低端手机更易发现瓶颈;

五、Profiling GPU Rendering

根据Android性能优化典范,打开设备的GPU配置渲染工具——》在屏幕上显示为条形图,可以协助我们定位UI渲染问题。

从Android M版本开始,GPU Profiling工具把渲染操作拆解成如下8个详细的步骤进行显示。

  1. Swap Buffers:表示处理任务的时间,也可以说是CPU等待GPU完成任务的时间,线条越高,表示GPU做的事情越多;
  2. Command Issue:表示执行任务的时间,这部分主要是Android进行2D渲染显示列表的时间,为了将内容绘制到屏幕上,Android需要使用Open GL ES的API接口来绘制显示列表,红色线条越高表示需要绘制的视图更多;
  3. Sync & Upload:表示的是准备当前界面上有待绘制的图片所耗费的时间,为了减少该段区域的执行时间,我们可以减少屏幕上的图片数量或者是缩小图片的大小;
  4. Draw:表示测量和绘制视图列表所需要的时间,蓝色线条越高表示每一帧需要更新很多视图,或者View的onDraw方法中做了耗时操作;
  5. Measure/Layout:表示布局的onMeasure与onLayout所花费的时间,一旦时间过长,就需要仔细检查自己的布局是不是存在严重的性能问题;
  6. Animation:表示计算执行动画所需要花费的时间,包含的动画有ObjectAnimator,ViewPropertyAnimator,Transition等等。一旦这里的执行时间过长,就需要检查是不是使用了非官方的动画工具或者是检查动画执行的过程中是不是触发了读写操作等等;
  7. Input Handling:表示系统处理输入事件所耗费的时间,粗略等于对事件处理方法所执行的时间。一旦执行时间过长,意味着在处理用户的输入事件的地方执行了复杂的操作;
  8. Misc Time/Vsync Delay:表示在主线程执行了太多的任务,导致UI渲染跟不上vSync的信号而出现掉帧的情况;出现该线条的时候,可以在Log中看到这样的日志:

备注:GPU配置渲染工具虽然可以定位出问题发生在某个步骤,但是并不能定位到具体的某一行;当我们定位到某个步骤之后可以使用工具TraceView进行更加详细的定位。TraceView的使用可以参照《Android性能优化(一)之启动加速35%》

六、Use Tags

merge标签

merge可以用来合并布局,减少布局的层级。merge多用于替换顶层FrameLayout或者include布局时,用于消除因为引用布局导致的多余嵌套。 例如:需要显示一个Button,布局如下;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Merge标签演示" />
</LinearLayout>

我们通过UiAutoMatorViewer(无需root,相比Hierarchy Viewer只能查看布局层次,不能得到绘制时间)看一下布局的层次

我们使用Merge标签对代码进行修改;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Merge标签演示" />
</merge>

再看下布局的层次:

可以看到使用Merge标签进行优化之后布局嵌套就少了一层,Button作为父视图第三层FrameLayout的直接子视图。

注意:merge标签常用于减少布局嵌套层次,但是只能用于根布局。

ViewStub标签

推迟创建对象、延迟初始化,不仅可以提高性能,也可以节省内存(初始化对象不被创建)。Android定义了ViewStub类,ViewStub是轻量级且不可见的视图,它没有大小,没有绘制功能,也不参与measure和layout,资源消耗非常低。 1、

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    <ViewStub
        android:id="@+id/mask"
        android:layout="@layout/b_me_mask"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ViewStub viewStub = (ViewStub)view.findViewById(R.id.mask);
viewStub.inflate();

App里常见的视图如蒙层、小红点,以及网络错误、没有数据等公共视图,使用频率并不高,如果每一次都参与绘制其实是浪费资源的,都可以借助ViewStub标签进行延迟初始化,仅当使用时才去初始化。

include标签

include标签和布局性能关系不大,主要用于布局重用,一般和merge标签配合使用,因和本文主题关联不大,此处不展开讨论。

七、其它

  1. 自定义控件时,注意在onDraw不能进行复杂运算;以及对待三方UI库选择高性能;
  2. 内存对布局的影响:如同Misc Time/Vsync Delay步骤产生的影响,在之后内存优化的篇章详细讲。

八、总结

布局优化的通用套路
  1. 调试GPU过度绘制,将Overdraw降低到合理范围内;
  2. 减少嵌套层次及控件个数,保持view的树形结构尽量扁平(使用Hierarchy Viewer可以方便的查看),同时移除所有不需要渲染的view;
  3. 使用GPU配置渲染工具,定位出问题发生在具体哪个步骤,使用TraceView精准定位代码;
  4. 使用标签,Merge减少嵌套层次、ViewStub延迟初始化。

经过这几步的优化之后,一般就不会再有布局的性能问题,同时还是要强调:优化是一个长期的工作,同时也必须结合具体场景:有取有舍!

参考:Android性能优化典范

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-02-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 双十二技术哥 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Android性能优化系列之布局优化
在Android开发中,UI布局可以说是每个App使用频率很高的,随着UI越来越多,布局的重复性、复杂度也会随之增长,这样使得UI布局的优化,显得至关重要,UI布局不慎,就会引起过度绘制,从而造成UI卡顿的情况,本篇博客,我就来总结一下UI布局优化的相关技巧。
老马的编程之旅
2022/06/22
1.1K0
Android性能优化系列之布局优化
性能优化之布局优化记录
做开发时间长了之后,收集后台的bug,发现很多都是OOM(Out Of Memory Killer)。性能优化这时候成为了重点,下面是自己项目中布局优化的记录,希望对大家有所帮助。
Jingbin
2018/09/10
4640
Android性能优化:这是一份详细的布局优化指南(含标签Include、Viewstub、Merge讲解)
针对 页面布局的性能、层级、测量绘制时间 进行优化,从而提高 Android应用中的页面显示速度
Carson.Ho
2021/12/06
2K0
Android性能优化:这是一份详细的布局优化指南(含标签Include、Viewstub、Merge讲解)
Android——卡顿优化布局篇(含学习资料分享)
在当下移动互联网后半场,手机已经是人手必备的设备。App是离用户最近的应用,界面又是最直观影响用户体验的关键部分,其流畅度直接影响用户对产品的评价和留存。
做个快乐的码农
2022/01/22
7961
Android——卡顿优化布局篇(含学习资料分享)
Android绘制优化(二)布局优化
前言 我们知道一个界面的测量和绘制是通过递归来完成的,减少布局的层数就会减少测量和绘制的时间,从而性能就会得到提升。当然这只是布局优化的一方面,那么如何来进行布局的分析和优化呢?本篇文章会给你一个满意的答案。 1.布局优化工具 在讲到如何去布局优化前,我们先来学习两种布局优化的工具。 Hierarchy Viewer Hierarchy Viewer是Android SDK自带的可视化的调试工具,用来检查布局嵌套和绘制的时间。需要注意的是在在Android的官方文档中提到:出于安全考虑,Hierarchy
用户1269200
2018/02/01
1.3K0
Android绘制优化(二)布局优化
Android性能优化-渲染优化
我们在开发的过程中,可能经常会遇到测试的一些反馈,就是APP运行卡顿的问题。我们通常所讲的卡顿问题都是因为渲染掉帧的问题引起视觉上的卡顿感。所以了解渲染机制,我们在项目的开发过程中,可以有意识的少挖坑。同时要打造一款精品的应用,注意渲染优化也是非常重要的一件事情。
Anymarvel
2018/10/22
1.5K0
Android性能优化-渲染优化
Android界面性能优化必读
Android系统要求每一帧都要在 16ms 内绘制完成,平滑的完成一帧意味着任何特殊的帧需要执行所有的渲染代码(包括 framework 发送给 GPU 和 CPU 绘制到缓冲区的命令)都要在 16ms 内完成,保持流畅的体验。这个速度允许系统在动画和输入事件的过程中以约 60 帧每秒( 1秒 / 0.016帧每秒 = 62.5帧/秒 )的平滑帧率来渲染。
做个快乐的码农
2022/01/10
4.9K0
Android界面性能优化必读
Android性能优化系列之渲染优化
众所周知的Android系统每隔16ms重新绘制一次activity,也就是说你的app必须在16ms内完成屏幕刷新的所有逻辑操作,这样才能达到60帧/s。而用户一般所看到的卡顿是由于Android的渲染性能造成的。 本篇博客将介绍Android的渲染相关知识。
老马的编程之旅
2022/06/22
1.1K0
Android性能优化系列之渲染优化
如何优化 Android 的布局性能?如何使用 ConstraintLayout 来减少嵌套层级?
优化 Android 布局性能是提升应用流畅性的关键步骤。以下是系统性优化方法,结合原理、工具和实际开发经验:
进击的阿斌
2025/02/13
3840
Android性能优化典范(1)
2015年伊始,Google发布了关于Android性能优化典范的专题,一共16个短视频,每个3-5分钟,帮助开发者创建更快更优秀的Android App。课程专题不仅仅介绍了Android系统中有关性能问题的底层工作原理,同时也介绍了如何通过工具来找出性能问题以及提升性能的建议。主要从三个方面展开,Android的渲染机制,内存与GC,电量优化。下面是对这些问题和建议的总结梳理。
WeTest质量开放平台团队
2018/10/29
6760
Android开发之布局优化
(1) <include>标签 include标签经常使用于将布局中的公共部分提取出来供其它layout共用,以实现布局模块化。这在布局编写方便提供了大大的便利。
全栈程序员站长
2022/07/08
3720
Android开发之布局优化
Android性能优化来龙去脉总结
一款app除了要有令人惊叹的功能和令人发指交互之外,在性能上也应该追求丝滑的要求,这样才能更好地提高用户体验。
用户1263954
2018/07/30
3450
Android性能优化来龙去脉总结
Android 优化——布局优化
理想情况下,60 FPS 以上就不会卡顿,就是 1 秒内要有 60 帧,所以每一帧要在 16ms 内绘制完成。如果一个页面无法在 16ms 内完成渲染,就会感到卡顿。
三流之路
2018/09/11
1.3K0
Android 优化——布局优化
Android性能优化:手把手带你全面了解绘制优化
很多 过度绘制是难以避免的,如 上述实例的 文字 & 背景导致的过度绘制;只能尽可能避免过度绘制:
Carson.Ho
2022/03/25
7990
Android性能优化:手把手带你全面了解绘制优化
[Android技术专题]应用开发进阶必经之路之性能优化(上)
性能优化在一款产品的迭代过程中非常重要;程序实现了功能、还原产品原型只能保证程序能用,但如果要让用户更愿意使用,产品得好用。试想一下如果你开发的产品启动慢、页面显示需要长时间转圈加载、页面切换卡顿、黑白屏、用一会机器就发烫、耗内存、OOM、程序切换到后台后占用内存无法释放......,这些问题就像正在玩游戏时弹出提示框这类糟糕的用户体验一样让用户恼火,如果用户不得不使用你的产品,可能还会一直忍受;但如果有很多同类竞品,糟糕的用户体验会大大影响留存率。有时候产品在市场上的表现差,真不能全怪产品和运营,程序体验问题也是很大一部分原因。
open
2020/03/19
7540
[Android技术专题]应用开发进阶必经之路之性能优化(上)
Android性能优化来龙去脉总结
一款app除了要有令人惊叹的功能和令人发指交互之外,在性能上也应该追求丝滑的要求,这样才能更好地提高用户体验。
WeTest质量开放平台团队
2018/06/08
1.6K3
Android性能优化来龙去脉总结
Android性能优化(六)之卡顿那些事
对普通用户而言,类如内存占用高、耗流量、耗电量等性能问题可能不会轻易发现,但是卡顿问题用户一定会立马直观的感受到。本文就带你一览卡顿的发生、检测、及优化。
用户2898788
2018/08/21
1.2K0
Android性能优化(六)之卡顿那些事
Android应用优化之流畅度实操
作者:guojun_fire https://juejin.im/post/5af815b3f265da0b93486566 本文由作者 guojun_fire 授权发布。 上一篇流畅度概念向大家详细地描述了VSync机制和Choreographer编舞者的用法。可能所讲解的内容偏向理论概念,因此这篇是流畅度优化实操,整篇主要分三层,UI层、代码逻辑层、IO层来讲述各个优化点,其中还会穿插多个辅助检测插件。可谓干货满满,希望对大家有用。 最基本的UI层显示优化 1.调试GPU过度渲染 在App出现卡顿的时
用户1269200
2018/06/22
1.3K0
Android性能优化:一份详细的布局优化实战指南,太特么重要了
对于Android开发者来说,懂得基本的应用开发技能往往是不够,因为不管是工作还是面试,都需要开发者懂得大量的性能优化,这对提升应用的体验是非常重要的。对于Android开发来说,性能优化主要围绕如下方面展开:启动优化、渲染优化、内存优化、网络优化、卡顿检测与优化、耗电优化、安装包体积优化、安全问题等。 下面是我整理了网上很多大佬的经验分享对Android性能优化做了一个总结。
用户9227784
2021/12/20
9630
Android性能优化:这些绘制优化你一定不能忽略!
<item name="windowBackground">@drawable/screen\_background\_selector\_light</item>
网易Leo
2021/12/12
1.1K0
相关推荐
Android性能优化系列之布局优化
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验