前言

最近Compose曾经正式公布了1.0版本,这阐明谷歌认为Compose曾经能够用于正式生产环境了
那么相比传统的XML,Compose的性能到底怎么样呢?

本文次要从构建性能与运行时两个方面来剖析Compose的性能,数据次要来源于:Jetpack Compose — Before and after 与 Measuring Render Performance with Jetpack Compose , 想理解更多的同学能够间接点击查看

构建性能

Compose构建性能次要以 tivi 为例来进行阐明
Tivi是一个开源的电影App,本来基于FragmentXML构建,同时还应用了DataBinding等应用了注解处理器的框架
起初迁徙到应用Compose构建UI,迁徙过程分为两步

  1. 第一步:迁徙到NavigationFragment,每个FragmentUI则由Compose构建
  2. 第二步:移除Fragment,齐全基于Compose实现UI

上面咱们就对Pre-Compose,Fragments + Compose,Entirely Compose三个阶段的性能进行剖析比照

APK体积

包体积是咱们常常关注的性能指标之一,咱们一起看下3个阶段的包体积比照



能够看出,TiviAPK 大小缩减了 46%,从 4.49MB 缩减到 2.39MB,同时办法数也缩小了17%

值得注意的是,在刚开始在利用中采纳Compose时,有时您会发现APK大小反而变大了
这是因为迁徙没有实现,老的依赖没有实现移除,而新的依赖曾经增加了,导致APK体积变大
而在我的项目齐全迁徙到Compose后,APK 大小会缩小,并且优于原始指标。

代码行数

咱们晓得在比拟软件我的项目时,代码行数并不是一个特地有用的统计数据,但它的确提供了对事物如何变动的一个察看指标。
咱们应用cloc工具来计算代码行数

cloc . --exclude-dir=build,.idea,schemas

后果如下图所示:

能够看出,在迁徙到Compose后,毫无意外的,XML代码行缩小了76%
乏味的是kotlin代码同样缩小了,可能是因为咱们能够缩小很多模板代码,同时也能够移除之前写的一些View Helper代码

构建速度

随着我的项目的一直变大,构建速度是开发人员越来越关怀的一个指标。
在开始重构之前,咱们晓得,删除大量的注解处理器会有助于进步构建速度,但咱们不确定会有多少。

咱们运行以下命令5次,而后取平均值

./gradlew --profile --offline --rerun-tasks --max-workers=4 assembleDebug

后果如下


这里思考的是调试构建工夫,您在开发期间会更关注此工夫。

在迁徙到Compose前,Tivi 的均匀构建工夫为 108.71 秒。
在齐全迁徙到 Compose 后,均匀构建工夫缩短至 76.96 秒!构建工夫缩短了 29%
构建工夫能缩短这么多,当然不仅仅是Compose的功绩,在很大水平上受两个因素的影响:

  1. 一个是移除了应用注解处理器的DataBindingEpoxy
  2. 另一个是HiltAGP 7.0 中的运行速度更快。

运行时性能

下面咱们介绍了Compose在构建时的性能,上面来看下Compose在运行时渲染的性能怎么样

剖析前的筹备

应用Compose时,可能有多种影响性能的指标

  • 如果咱们齐全在Compose中构建UI会怎么?
  • 如果咱们对简单视图应用Compose(例如用 LazyColumn 替换 RecyclerViews),但根布局依然增加在XML
  • 如果咱们应用Compose替换页面中一个个元素,而不是整个页面,会怎么样?
  • 是否可调试和R8编译器对性能的影响有多大?

为了开始答复这些问题,咱们构建了一个简略的测试程序。
在第一个版本中,咱们增加了一个蕴含50个元素的列表(其中理论绘制了大概 12 个)。该列表包含一个单选按钮和一些随机文本。


为了测试各种选项的影响,咱们增加以下4种配置,以下4种都是开启了R8同时敞开了debug

  1. 纯Compose
  2. 一个XML中,只带有一个ComposeView,具体布局写在Compose
  3. XML中只蕴含一个RecyclerView,然而RecyclerView的每一项是一个ComposeView
  4. XML

同时为了测试build type对性能的影响,也增加了以下3种配置

  1. Compose,敞开R8并关上debug
  2. Compose,敞开R8并敞开debug
  3. XML,敞开R8并关上debug

如何定义性能?

Compose运行时性能,咱们个别了解的就是页面启动到用户看到内容的工夫
因而上面几个机会对咱们比拟重要

  1. Activity启动工夫,即onCreate
  2. Activity启动实现工夫,即onResume
  3. Activity渲染绘制实现工夫,即用户看到内容的工夫

onCreateonResume的机会很容易把握,重写零碎办法即可,但如何取得Activity齐全绘制的工夫呢?
咱们能够给页面根View增加一个ViewTreeObserver,而后记录最初一次onDraw调用的工夫

应用Profile查看下面说的过程,如下别离为应用XML渲染与应用Compose渲染的具体过程,即从OnCreate到调用最初一次onDraw的过程


渲染性能剖析

晓得了如何定义性能,咱们就能够开始测试了

  1. 每次测试都在几台设施上运行,包含最近的旗舰、没有Google Play服务的设施和一些便宜手机。
  2. 每次测试在同一台手机上都会运行10次,因而咱们不仅能够获取首次渲染工夫,也能够获取二次渲染工夫
  3. 测试Compose版本为1.0.0

咱们依据下面定义的配置,反复跑了屡次,失去了一些数据,感兴趣的同学能够间接查看所有数据


剖析后果如上图所示,咱们能够得出一些论断

  • R8和是否可调试对Jetpack Compose渲染工夫产生了显着影响。在每次试验中,禁用R8和启用可调试性的构建所破费的工夫是没有它们的构建的两倍多。在咱们最慢的设施上,R8 将渲染速度放慢了半秒以上,而禁用debug又使渲染速度放慢了半秒。
  • XML中只蕴含一个ComposeView的渲染工夫,跟纯Compose的耗时差不多
  • RecyclerView中蕴含多个ComposeView是最慢的。这并不奇怪,在XML中应用ComposeView是有老本的,所以页面中应用的ComposeView越少越好。
  • XML在出现方面比Compose更快。没有方法解决这个问题,在每种状况下,Compose 的渲染工夫比 XML 长约 33%。
  • 第一次启动总是比后续启动破费更长的工夫来渲染。如果您查看残缺的数据,第一个页面的渲染工夫简直是后续的两倍。

比拟让我诧异的是,只管Compose没有了将XML转化成ViewIO操作,测量过程也因为固有个性测量进步了测量效率,但性能依然比XML要差
不过,依据Leland Richardson的说法,当从Google Play装置应用程序时,因为捆绑的AOT编译,Compose 在启动时渲染会更快,从而进一步放大了与XML的差距

总结

通过上面对Compose性能方面的剖析,总结如下

  1. 如果齐全迁徙到Compose,在包体积,代码行数,编译速度等方面应该会有比拟大的改善
  2. 如果处于迁徙中的阶段,可能因为旧的依赖没有去除,而曾经引入了新的依赖,反而导致包体积等变大
  3. 只管没有了XML转换的IO操作,测量过程也通过固有个性测量进行了优化,Compose的渲染性能比起XML依然有肯定差距
  4. 只管目前Compose在性能方面略有欠缺(在大多数设施上仅超过一两帧),但因为其在开发人员生产力、代码重用和申明式UI的弱小个性等方面的劣势,Compose仍被举荐应用
视频:Android开发中高级进阶:JetPack Compse开发利用实战
原文: https://juejin.cn/post/7008522702835154980