优化布局层次结构

尝试 Compose 方式
Jetpack Compose 是 Android 推荐的 UI 工具包。了解如何在 Compose 中使用布局。

人们普遍误以为使用基本布局结构会导致最有效的布局。然而,您在应用程序中添加的每个小部件和布局都需要初始化、布局和绘制。例如,使用 LinearLayout 的嵌套实例会导致视图层次结构过深。此外,嵌套多个使用 layout_weight 参数的 LinearLayout 实例可能特别昂贵,因为每个子元素都需要测量两次。这在布局重复膨胀时尤为重要,例如在 RecyclerView 中使用时。

本文档介绍了如何使用 布局检查器lint 检查和优化您的布局。

检查您的布局

Android SDK 工具包括 布局检查器 工具,它允许您在应用程序运行时分析您的布局。使用此工具有助于您发现布局性能中的低效率。

布局检查器允许您选择连接的设备或模拟器上的正在运行的进程,然后显示布局树。每个块上的交通灯代表其测量、布局和绘制性能,帮助您识别潜在问题。

例如,图 1 显示了一个用作 RecyclerView 中项目的布局。此布局在左侧显示一个小位图图像,在右侧显示两个堆叠的文本项。优化此类布局尤为重要,因为此类布局会被多次膨胀,因为性能优势会成倍增加。

An image showing a single item in a list: one image and two vertically aligned texts
图 1. RecyclerView 中项目的概念布局。

布局检查器显示可用设备及其正在运行的组件的列表。从窗口选项卡中选择您的组件,然后单击布局检查器以查看所选组件的布局层次结构。例如,图 2 显示了图 1 中说明的列表项的布局。

An image showing Layout Inspector and the LinearLayout composition
图 2. 使用 LinearLayout 的嵌套实例,针对图 1 中布局的布局层次结构。

修改您的布局

由于前面的布局性能由于嵌套的 LinearLayout 而变慢,因此您可以通过扁平化布局来提高性能,换句话说,使布局变浅变宽,而不是变窄变深。ConstraintLayout 作为根节点允许使用此类布局。当您将此设计转换为使用 ConstraintLayout 时,布局将变为两级层次结构

    <androidx.constraintlayout.widget.ConstraintLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"
      xmlns:tools="http://schemas.android.com/tools"
      android:id="@+id/root"
      android:layout_width="match_parent"
      android:layout_height="52dp"
      android:background="#e4e6e4"
      android:padding="4dp">

      <ImageView
          android:id="@+id/image"
          android:layout_width="48dp"
          android:layout_height="48dp"
          android:background="#5c5c74"
          android:contentDescription="An example box"
          app:layout_constraintBottom_toBottomOf="parent"
          app:layout_constraintStart_toStartOf="parent"
          app:layout_constraintTop_toTopOf="parent" />

      <TextView
          android:id="@+id/title"
          android:layout_width="0dp"
          android:layout_height="0dp"
          android:layout_marginStart="4dp"
          android:background="#745c74"
          app:layout_constraintBottom_toTopOf="@+id/subtitle"
          app:layout_constraintEnd_toEndOf="parent"
          app:layout_constraintStart_toEndOf="@id/image"
          app:layout_constraintTop_toTopOf="parent" />

      <TextView
          android:id="@+id/subtitle"
          android:layout_width="0dp"
          android:layout_height="0dp"
          android:background="#7e8d6e"
          app:layout_constraintBottom_toBottomOf="parent"
          app:layout_constraintEnd_toEndOf="parent"
          app:layout_constraintStart_toStartOf="@id/title"
          app:layout_constraintTop_toBottomOf="@+id/title" />
  </androidx.constraintlayout.widget.ConstraintLayout>
    

新布局的检查如下所示

An image showing the 3D Layout Inspector
图 3. 布局检查器 3D 模式。

这样做的好处是成倍增加的,因为此布局用于列表中的每个项目。

大部分区别是由于在 LinearLayout 设计中使用了 layout_weight,这会减慢测量速度。这是一个关于每个布局都有其适当用法的示例。仔细考虑是否需要使用布局权重。

在某些复杂的布局中,系统可能会浪费精力多次测量相同的 UI 元素。这种现象称为双重征税。有关双重征税以及如何防止双重征税的更多信息,请参阅 性能和视图层次结构

使用 lint

最佳实践是在您的布局文件上运行 lint 工具以搜索可能的视图层次结构优化。Lint 替换了 layoutopt 工具,并具有更多功能。以下是一些 lint 规则 的示例

  • 使用复合可绘制对象。您可以更有效地将包含 ImageViewTextViewLinearLayout 处理为复合可绘制对象。
  • 合并根框架。如果布局的根是 FrameLayout,它不提供背景或填充,您可以用合并标记替换它,合并标记效率略高。
  • 删除无用的叶子。您可以删除没有子元素或没有背景的布局,因为它不可见,从而获得更扁平、更有效的布局层次结构。
  • 删除无用的父元素。您可以删除具有子元素但没有兄弟元素、不是 ScrollView 或根布局并且没有背景的布局。您也可以将子视图直接移动到父元素中,以获得更扁平、更有效的布局层次结构。
  • 避免深度布局。嵌套过多的布局会影响性能。考虑使用更扁平的布局,例如 ConstraintLayout,以提高性能。lint 检查的默认最大深度为 10。

lint 工具的另一个好处是它与 Android Studio 集成在一起。每当您编译程序时,lint 都会自动运行。使用 Android Studio,您还可以针对特定构建变体或所有构建变体运行 lint 检查。

您还可以使用文件 > 设置 > 项目设置选项在 Android Studio 中管理检查配置文件和配置检查。检查配置页面将显示支持的检查

An image showing Android Studio Inspections menu
图 4. 检查配置页面。

lint 可以自动修复某些问题,针对其他问题提供建议,并直接跳转到相关代码以供审查。

有关更多信息,请参阅 布局布局资源