Android 性能与视图层次结构查看,检查布局性能
ztj100 2024-11-22 00:13 53 浏览 0 评论
对 View 对象层次结构的管理方式会显著影响应用的性能。本页介绍如何评估视图层次结构是否减慢了应用的速度,并且还提供了一些针对可能出现的问题的解决策略。
布局和度量性能
渲染流水线包含“布局和度量”阶段,系统在此阶段以适当的方式将相关项放置在视图层次结构中。此阶段的度量部分确定 View 对象的大小和边界,布局部分确定 View 对象在屏幕上的放置位置。
这两个流水线阶段在处理每个视图或布局时,都会产生少量开销。在大多数情况下,此开销很小,不会明显影响性能。不过,当应用添加或移除 View 对象时(例如在 RecyclerView 对象回收或重用 View 对象时),此开销会变大。如果 View 对象需要考虑调整大小来保持其约束,此开销也会增加:例如,如果您的应用对包围文本的 View 对象调用 SetText(),View 可能需要调整大小。
如果这类操作花费的时间太长,可能会导致帧无法在允许的 16 毫秒内完成渲染,从而造成丢帧并使动画变得粗糙。
由于您无法将这些操作移至工作器线程(您的应用必须在主线程上处理这些操作),因此最好的选择是对它们进行优化,使其花费尽可能少的时间。
管理复杂性:布局很重要
Android 布局允许您将界面对象嵌套在视图层次结构中。这种嵌套也会增加布局开销。当应用处理布局对象时,也会对布局的所有的对象执行相同的处理。对于复杂的布局,有时仅在系统第一次计算布局时才会产生开销。例如,当应用在 RecyclerView 对象中回收复杂的列表项时,系统需要列出所有对象。又如,细微的更改可以往上朝父级传播,直至到达不影响父级大小的对象为止。
布局耗时过长最常见的情况是,View 对象的层次结构互相嵌套。每个嵌套的布局对象都会增加布局阶段的开销。层次结构越扁平,完成布局阶段所需的时间越少。
如果使用 RelativeLayout 类,则可通过使用未设权重的嵌套 LinearLayout 视图,以更低的开销达到同样的效果。此外,如果您的应用面向 Android 7.0(API 级别 24)或更高版本,您可以使用特殊的布局编辑器来创建 ConstraintLayout 对象,而非 RelativeLayout。这样做可以避免本节中讲到的许多问题。ConstraintLayout 类提供类似的布局控制,但性能大大提高。该类使用自己的约束解析系统,采用与标准布局完全不同的方式来解析视图之间的关系。
Double Taxation
通常情况下,框架会在一次遍历中快速执行布局或度量阶段。但在一些情况比较复杂的布局中,在最终放置元素之前,框架可能必须对层次结构中需要多次遍历才能解析的部分执行多次迭代。必须执行不止一次“布局和度量”迭代的情况称为“Double Taxation”。
例如,当您使用 RelativeLayout 容器时(该容器允许您根据其他 View 对象的位置来放置 View 对象),框架会执行以下操作:
- 执行一次“布局和度量”遍历。在此过程中,框架会根据每个子对象的请求计算该子对象的位置和大小。
- 结合此数据和对象的权重确定关联视图的恰当位置。
- 执行第二次布局遍历,以最终确定对象的位置。
- 进入渲染过程的下一个阶段。
视图层次结构的层次越多,潜在的性能损失就越大。
此外,RelativeLayout 以外的容器也可能会导致 Double Taxation。例如:
- 将 LinearLayout 视图设置为水平方向,可能会导致执行双重“布局和度量”遍历。如果您添加 measureWithLargestChild,则垂直方向上也可能会发生双重“布局和度量”变化,因为在这种情况下,框架可能需要执行第二次遍历才能正确解析对象的大小。
- GridLayout 也有类似的问题。虽然该容器也允许相对定位,但它通常会通过预处理子视图之间的位置关系来避免 Double Taxation。不过,如果布局使用权重或使用 Gravity 类来填充,则会失去该预处理带来的好处,当容器为 RelativeLayout 时,框架可能必须执行多次遍历。
多次“布局和度量”遍历本身并不是性能负担,但如果发生在错误的地方,就可能会变成负担。您应该警惕容器存在以下情况:
- 它是视图层次结构中的根元素。
- 它下面有较深的视图层次结构。
- 屏幕中填充了它的许多实例,类似于 ListView 对象中的子对象。
诊断视图层次结构问题
布局性能是一个涉及许多方面的复杂问题。有几种工具可以为您提供关于性能瓶颈发生位置的明确提示。其他一些工具提供的信息不那么明确,但也能提供有用的提示。
Systrace
有一个工具可以提供关于性能的重要数据,那就是 Systrace,该工具内置在 Android SDK 中。利用 Systrace 工具,您可以在整个 Android 设备上收集和检查计时信息,从而了解布局性能问题何时导致性能问题。要详细了解 Systrace,请参阅系统跟踪概览。
GPU 渲染分析
另一款最有可能为您提供可靠的性能瓶颈信息的工具是设备端 GPU 渲染分析工具,该工具在搭载 Android 6.0(API 级别 23)及更高版本的设备上提供。通过此工具,您可以了解“布局和度量”阶段在每一帧渲染上花费的时间。此数据可以帮助您诊断运行时性能问题,以及确定需要解决哪些“布局和度量”问题(如果有)。
在其捕获的数据的图形表示中,GPU 渲染分析使用蓝颜色来代表布局时间。要详细了解如何使用此工具,请参阅 GPU 渲染分析演示。
Lint
Android Studio 的 Lint 工具可以帮助您了解视图层次结构中的低效问题。要使用此工具,请依次选择 Analyze > Inspect Code,如图 1 中所示。
图 1. 在 Android Studio 中找到 Inspect Code。
Android > Lint > Performance 下面显示了有关各种布局项目的信息。要查看更多详情,可以点击各个项目将其展开,然后在屏幕右侧的窗格中会显示详细信息。图 2 显示了此界面的一个示例。
图 2. 查看有关 Lint 工具发现的特定问题的信息。
点击其中一个项目,右侧窗格中就会显示与该项目相关的问题。
要详细了解该区域中显示的特定主题和问题,请参阅 Lint 文档。
Layout Inspector
Android Studio 的 Layout Inspector 工具提供关于应用视图层次结构的可视化表示。这是一种浏览应用层次结构的好方法,它提供关于特定视图父链的清晰的可视化表示,可帮助您检查应用构建的布局。
Layout Inspector 提供的视图还可以帮助您确定由“Double Taxation”引起的性能问题。它还可以让您通过一种简便的方法来识别嵌套布局的深层链或具有大量嵌套智能的布局区域,这是导致性能下降的另一个潜在因素。在这两种情况下,“布局和度量”阶段的开销可能会特别大,从而导致性能问题。
要了解详情,请参阅使用 Layout Inspector 调试布局。
解决视图层次结构问题
要解决由视图层次结构引起的性能问题,其背后的基本原理很简单,但实际操作起来却比较困难。防止因视图层次结构导致性能下降包括两个目标:一个是实现视图层次结构扁平化,一个是减少“Double Taxation”。本节将探讨实现这两个目标的一些策略。
移除多余的嵌套布局
开发者经常会过度使用嵌套布局。例如,可能会在 RelativeLayout 容器包含一个同样也是 RelativeLayout 容器的子级。这种嵌套实际是多余的,并且会给视图层次结构造成不必要的开销。
Lint 通常可以为您标记此类问题,从而减少调试时间。
采用 merge/include
造成多余嵌套布局的一个常见原因就是 <include> 标记。例如,您可以定义一个类似如下的可重复使用的布局:
<LinearLayout> <!-- some stuff here --> </LinearLayout>
然后,定义一个 include 标记将此项目添加到父容器中:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/app_bg" android:gravity="center_horizontal">
<include layout="@layout/titlebar"/>
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/hello" android:padding="10dp" />
...
</LinearLayout>
该 include 会将第一个布局嵌套在第二个布局中,而此嵌套是不必要的。
merge 标记可以避免此问题。要了解此标记,请参阅通过 <include> 重复使用布局。
采用开销较低的布局
您可能无法调整现有的布局方案,使其不包含多余的布局。在某些情况下,唯一的解决方案可能是,通过切换到完全不同的布局类型来实现层次结构的扁平化。
例如,您可能会发现,TableLayout 作为具有许多位置依赖项的更复杂的布局,可以提供相同的功能。在 Android 的 N 版本中,ConstraintLayout 类提供了与 RelativeLayout 类似的功能,但开销要低得多。
相关推荐
- sharding-jdbc实现`分库分表`与`读写分离`
-
一、前言本文将基于以下环境整合...
- 三分钟了解mysql中主键、外键、非空、唯一、默认约束是什么
-
在数据库中,数据表是数据库中最重要、最基本的操作对象,是数据存储的基本单位。数据表被定义为列的集合,数据在表中是按照行和列的格式来存储的。每一行代表一条唯一的记录,每一列代表记录中的一个域。...
- MySQL8行级锁_mysql如何加行级锁
-
MySQL8行级锁版本:8.0.34基本概念...
- mysql使用小技巧_mysql使用入门
-
1、MySQL中有许多很实用的函数,好好利用它们可以省去很多时间:group_concat()将取到的值用逗号连接,可以这么用:selectgroup_concat(distinctid)fr...
- MySQL/MariaDB中如何支持全部的Unicode?
-
永远不要在MySQL中使用utf8,并且始终使用utf8mb4。utf8mb4介绍MySQL/MariaDB中,utf8字符集并不是对Unicode的真正实现,即不是真正的UTF-8编码,因...
- 聊聊 MySQL Server 可执行注释,你懂了吗?
-
前言MySQLServer当前支持如下3种注释风格:...
- MySQL系列-源码编译安装(v5.7.34)
-
一、系统环境要求...
- MySQL的锁就锁住我啦!与腾讯大佬的技术交谈,是我小看它了
-
对酒当歌,人生几何!朝朝暮暮,唯有己脱。苦苦寻觅找工作之间,殊不知今日之事乃我心之痛,难道是我不配拥有工作嘛。自面试后他所谓的等待都过去一段时日,可惜在下京东上的小金库都要见低啦。每每想到不由心中一...
- MySQL字符问题_mysql中字符串的位置
-
中文写入乱码问题:我输入的中文编码是urf8的,建的库是urf8的,但是插入mysql总是乱码,一堆"???????????????????????"我用的是ibatis,终于找到原因了,我是这么解决...
- 深圳尚学堂:mysql基本sql语句大全(三)
-
数据开发-经典1.按姓氏笔画排序:Select*FromTableNameOrderByCustomerNameCollateChinese_PRC_Stroke_ci_as//从少...
- MySQL进行行级锁的?一会next-key锁,一会间隙锁,一会记录锁?
-
大家好,是不是很多人都对MySQL加行级锁的规则搞的迷迷糊糊,一会是next-key锁,一会是间隙锁,一会又是记录锁。坦白说,确实还挺复杂的,但是好在我找点了点规律,也知道如何如何用命令分析加...
- 一文讲清怎么利用Python Django实现Excel数据表的导入导出功能
-
摘要:Python作为一门简单易学且功能强大的编程语言,广受程序员、数据分析师和AI工程师的青睐。本文系统讲解了如何使用Python的Django框架结合openpyxl库实现Excel...
- 用DataX实现两个MySQL实例间的数据同步
-
DataXDataX使用Java实现。如果可以实现数据库实例之间准实时的...
- MySQL数据库知识_mysql数据库基础知识
-
MySQL是一种关系型数据库管理系统;那废话不多说,直接上自己以前学习整理文档:查看数据库命令:(1).查看存储过程状态:showprocedurestatus;(2).显示系统变量:show...
- 如何为MySQL中的JSON字段设置索引
-
背景MySQL在2015年中发布的5.7.8版本中首次引入了JSON数据类型。自此,它成了一种逃离严格列定义的方式,可以存储各种形状和大小的JSON文档,例如审计日志、配置信息、第三方数据包、用户自定...
你 发表评论:
欢迎- 一周热门
-
-
MySQL中这14个小玩意,让人眼前一亮!
-
旗舰机新标杆 OPPO Find X2系列正式发布 售价5499元起
-
【VueTorrent】一款吊炸天的qBittorrent主题,人人都可用
-
面试官:使用int类型做加减操作,是线程安全吗
-
C++编程知识:ToString()字符串转换你用正确了吗?
-
【Spring Boot】WebSocket 的 6 种集成方式
-
PyTorch 深度学习实战(26):多目标强化学习Multi-Objective RL
-
pytorch中的 scatter_()函数使用和详解
-
与 Java 17 相比,Java 21 究竟有多快?
-
基于TensorRT_LLM的大模型推理加速与OpenAI兼容服务优化
-
- 最近发表
- 标签列表
-
- idea eval reset (50)
- vue dispatch (70)
- update canceled (42)
- order by asc (53)
- spring gateway (67)
- 简单代码编程 贪吃蛇 (40)
- transforms.resize (33)
- redisson trylock (35)
- 卸载node (35)
- np.reshape (33)
- torch.arange (34)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- vue foreach (34)
- idea设置编码为utf8 (35)
- vue 数组添加元素 (34)
- std find (34)
- tablefield注解用途 (35)
- python str转json (34)
- java websocket客户端 (34)
- tensor.view (34)
- java jackson (34)
- vmware17pro最新密钥 (34)
- mysql单表最大数据量 (35)