优化布局层次结构

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

使用基本的布局结构可打造最高效的布局,这是一种常见的误解。不过,您添加到应用中的每个 widget 和布局都需要进行初始化、布局和绘制。例如,使用嵌套的 LinearLayout 实例可能会导致视图层次结构过深。此外,嵌套多个使用 layout_weight 参数的 LinearLayout 实例成本非常高,因为每个子级都需要测量两次。当布局反复膨胀时(例如,在 RecyclerView 中使用时),这一点尤为重要。

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

检查布局

Android SDK 工具包含 Layout Inspector 工具,可让您在应用运行时分析布局。此工具可帮助您发现布局性能低效的问题。

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

例如,图 1 显示了用作 RecyclerView 中的一项的布局。此布局左侧显示了一张小小的位图,而右侧则显示了两个堆叠的文本元素。尤其重要的是,您应对此类多次膨胀的布局进行优化,因为这会使性能优势成倍地提升。

一张显示列表中的单个项目的图片:一张图片和两个垂直对齐的文字
图 1. RecyclerView 中的一项的概念性布局。

布局检查器会显示可用设备及其正在运行的组件的列表。从 Windows 标签页中选择您的组件,然后点击 Layout Inspector 查看所选组件的布局层次结构。例如,图 2 显示了图 1 所示列表项的布局。

展示布局检查器和 LinearLayout 组合的图片
图 2. 图 1 所示布局的布局层次结构,使用嵌套的 LinearLayout 实例。

修改布局

由于上述布局的性能因嵌套的 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>
    

检查新布局是否如下所示:

显示 3D 布局检查器的图片
图 3. 布局检查器的 3D 模式。

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

大部分差异都是由在 LinearLayout 设计中使用 layout_weight 造成的,这会减慢测量速度。此示例展示了每种布局如何合理使用。请仔细考虑是否有必要使用布局权重。

在一些复杂的布局中,系统可能会浪费时间和资源来多次测量同一个界面元素。这种现象称为 Double Taxation。如需详细了解 Double Taxation 以及如何防止出现这种情况,请参阅性能和视图层次结构

使用 lint

最好对布局文件运行 lint 工具来搜索可能的视图层次结构优化机会。Lint 取代了 layoutopt 工具,并拥有更强大的功能。以下是 lint 规则的示例:

  • 使用复合可绘制对象。您可以更高效地处理包含 ImageViewTextViewLinearLayout 作为复合可绘制对象。
  • 合并根帧。如果布局的根部是不提供背景或内边距的 FrameLayout,您可以将其替换为 merge 标记,这样效率稍高一些。
  • 去掉无用的叶子。您可以移除没有子级或没有背景的布局(因为它不可见),以使布局层次结构更加扁平高效。
  • 移除无用的家长。您可以移除具有没有同级、不是 ScrollView 或根布局且没有背景的子项的布局。您还可以将子视图直接移动到父视图,以使布局层次结构更加扁平高效。
  • 避免使用深层布局。嵌套过多的布局会降低性能。请考虑使用比较扁平的布局(例如 ConstraintLayout)来提高性能。lint 检查的默认深度上限为 10。

lint 工具的另一个好处是它可以集成到 Android Studio 中。lint 会在您编译程序时自动运行。借助 Android Studio,您还可以针对特定 build 变体或所有 build 变体运行 lint 检查。

您还可以在 Android Studio 中通过 File > Settings > Project Settings 选项管理检查配置文件和配置检查。系统随即会显示“Inspection Configuration”页面,其中包含支持的检查:

显示 Android Studio“Inspections”菜单的图片
图 4. “Inspection Configuration”页面。

lint 可以自动修复某些问题、提供针对其他问题的建议,并直接跳转到违规代码进行审核。

如需了解详情,请参阅布局布局资源