比较 Compose 和 View 指标

Jetpack Compose 可加快界面开发速度并改进 Android 开发。但是,请考虑将 Compose 添加到现有应用可能会如何影响 APK 大小、构建和运行时性能等指标。

APK 大小和构建时间

本部分将通过查看 Sunflower 示例应用(该应用展示了将基于 View 的应用迁移到 Compose 的最佳实践)来介绍对 APK 大小和构建时间的影响。

APK 大小

向项目添加库会增加其 APK 大小。以下结果是每个项目的最小化发布版 APK 的结果,已启用资源和代码压缩,使用 R8 完整模式,并通过 APK Analyzer 进行测量。

仅限 View View 和 Compose 混合 仅限 Compose
下载大小 2,252 KB 3,034 KB 2,966 KB

首次将 Compose 添加到 Sunflower 时,APK 大小从 2,252 KB 增加到 3,034 KB,增加了 782 KB。生成的 APK 包含 View 和 Compose 混合的 UI 构建。这种增加是意料之中的,因为 Sunflower 中添加了额外的依赖项。

相反,当 Sunflower 迁移到仅限 Compose 的应用时,APK 大小从 3,034 KB 减少到 2,966 KB,减少了 68 KB。这种减少是由于移除了未使用的 View 依赖项,例如 AppCompatConstraintLayout

构建时间

添加 Compose 会增加应用的构建时间,因为 Compose 编译器会处理应用中的可组合项。以下结果是使用独立的 gradle-profiler 工具获得的,该工具会多次执行构建,以便获得 Sunflower 调试构建持续时间的平均构建时间

gradle-profiler --benchmark --project-dir . :app:assembleDebug
仅限 View View 和 Compose 混合 仅限 Compose
平均构建时间 299.47 ms 399.09 ms 342.16 ms

首次将 Compose 添加到 Sunflower 时,平均构建时间从 299 毫秒增加到 399 毫秒,增加了 100 毫秒。此持续时间是由于 Compose 编译器执行额外任务以转换项目中定义的 Compose 代码。

相反,当 Sunflower 完成向 Compose 的迁移时,平均构建时间降至 342 毫秒,减少了 57 毫秒。这种减少可归因于多种因素共同减少了构建时间,例如移除数据绑定、将使用 kapt 的依赖项迁移到 KSP,以及将多个依赖项更新到最新版本。

总结

采用 Compose 将有效增加应用的 APK 大小,并且由于 Compose 代码的编译过程,还会增加应用的构建时间性能。然而,这些权衡需要与Compose 的优势进行衡量,尤其是在采用 Compose 时开发人员生产力的提高。例如,Play 商店团队发现,编写 UI 需要的代码量大大减少,有时甚至高达 50%,从而提高了代码的生产力和可维护性。

您可以在为团队采用 Compose 中阅读更多案例研究。

运行时性能

本部分介绍了 Jetpack Compose 中与运行时性能相关的主题,旨在帮助您了解 Jetpack Compose 与 View 系统性能的对比,以及如何衡量它。

智能重组

当界面的某些部分无效时,Compose 会尝试仅重组需要更新的部分。如需详细了解此内容,请参阅可组合项生命周期Jetpack Compose 阶段文档。

基准配置文件

基准配置文件是加快常见用户历程的绝佳方法。在应用中包含基准配置文件可将代码执行速度从首次启动时提高约 30%,因为它可以避免对包含的代码路径进行解释和即时 (JIT) 编译步骤。

Jetpack Compose 库包含自己的基准配置文件,当您在应用中使用 Compose 时,会自动获得这些优化。但是,这些优化只会影响 Compose 库中的代码路径,因此我们建议您为您的应用添加基准配置文件,以覆盖 Compose 之外的代码路径。

与 View 系统的比较

Jetpack Compose 比 View 系统有许多改进。这些改进将在以下部分中介绍。

所有内容都扩展 View

在屏幕上绘制的每个 View(例如 TextViewButtonImageView)都需要内存分配、显式状态跟踪和各种回调来支持所有用例。此外,自定义 View 所有者需要实现显式逻辑,以防止在不必要时重新绘制——例如,对于重复的数据处理。

Jetpack Compose 以多种方式解决了这个问题。Compose 没有用于绘制视图的显式可更新对象。UI 元素是简单的可组合函数,其信息以可重播的方式写入组合。这有助于将显式状态跟踪、内存分配和回调限制为仅需要这些功能的可组合项,而不是要求给定 View 类型的所有扩展都具备这些功能。

此外,如果不需要进行更改,Compose 还提供智能重组,重播之前绘制的结果。

多次布局过程

传统的 ViewGroup 在其测量和布局 API 中具有很大的表达性,这使得它们容易出现多次布局过程。如果在视图层次结构中的特定嵌套点进行,这些多次布局过程可能会导致指数级的工作量。

Jetpack Compose 通过其 API 契约强制所有布局可组合项执行单次布局过程。这使得 Compose 能够高效地处理深层 UI 树。如果需要多次测量,Compose 具有固有测量功能。

View 启动性能

View 系统在首次显示特定布局时需要膨胀 XML 布局。在 Jetpack Compose 中,此成本得以节省,因为布局是用 Kotlin 编写的,并像应用的其余部分一样进行编译。

基准测试 Compose

在 Jetpack Compose 1.0 中,应用在 debug 模式和 release 模式下的性能存在显著差异。为获得具有代表性的时间,在分析应用时始终使用 release 构建,而不是 debug 构建。

要检查您的 Jetpack Compose 代码的性能,您可以使用 Jetpack Macrobenchmark 库。要了解如何在 Jetpack Compose 中使用它,请参阅 MacrobenchmarkSample 项目

Jetpack Compose 团队还使用 Macrobenchmark 来捕获可能发生的任何回归。例如,请参阅惰性列的基准测试及其控制面板以跟踪回归。

Compose 配置文件安装

由于 Jetpack Compose 是一个非捆绑库,它无法受益于预加载 View 系统 UI 工具包类和可绘制对象的 Zygote。Jetpack Compose 1.0 利用配置文件安装来实现 release 构建。配置文件安装器允许应用指定在安装时进行预先 (AOT) 编译的关键代码。Compose 附带的配置文件安装规则可减少 Compose 应用的启动时间和卡顿。