preface
Compose has recently been released in version 1.0, which shows that Google considers Compose ready for use in formal production environments. How does Compose perform compared to traditional XML?
In this article, Compose’s performance is analyzed from two aspects: build performance and runtime. The data comes from: Measuring Render Performance with Jetpack Compose – Before and after – Measuring Render Performance with Jetpack Compose
Building performance
Tivi is an open source movie App. Tivi was originally built based on Fragment and XML, and used DataBinding and other frameworks that used annotation processors. Later, tivi migrated to Compose for UI construction
- Step 1: Migrate to
Navigation
withFragment
, eachFragment
theUI
By theCompose
build - Step 2: Remove
Fragment
Completely based onCompose
implementationUI
Now let’s compare and analyze the performance of pre-compose,Fragments + Compose, and Entirely Compose
APK
volume
Package volume is one of the performance metrics we always focus on. Let’s take a look at the package volume comparison for the three phases
As you can see,Tivi
的 APK
Reduced in size46%
, from4.49 MB
Cut to2.39 MB
, and the number of methods is also reduced17%
It is important to note that when you first start using Compose in your application, you will sometimes find that the APK size actually increases. This is because the migration is not complete. The old dependencies have not been removed and new dependencies have been added, resulting in a larger APK size and a smaller APK size when the project is fully migrated to Compose. And better than the original indicators.
Lines of code
We know that lines of code are not a particularly useful statistic when comparing software projects, but it does provide an observation of how things are changing. We use cloC tools to count lines of code
cloc . --exclude-dir=build,.idea,schemas
Copy the code
The results are shown below:
As you can see, the migration toCompose
And then, not surprisingly,XML
There are fewer lines of code76%
It is interesting to notekotlin
The code is also reduced, probably because we can reduce a lot of template code and also remove some of the code we wrote earlierView Helper
code
Build speed
As projects get bigger, build speed is a metric that developers increasingly care about. Before we started refactoring, we knew that removing a lot of annotation handlers would help speed up the build, but we weren’t sure how much.
We run the following command five times and take the average
./gradlew --profile --offline --rerun-tasks --max-workers=4 assembleDebug
Copy the code
The results are as follows
The consideration here is debug build time, which you will be more concerned with during development.
Tivi’s average build time before migrating to Compose was 108.71 seconds. With full migration to Compose, the average build time was reduced to 76.96 seconds! Build time was reduced by 29%. Compose is not the only contributor that can shorten the build time by this much, but is largely due to two factors:
- One is to remove the annotation handler
DataBinding
andEpoxy
- The other one is
Hilt
inAGP 7.0
Is faster.
Runtime performance
Now that we’ve seen Compose’s performance at build time, let’s take a look at how well Compose performs at run time
Preparation before analysis
When using Compose, you can have several metrics that affect performance
- If we were completely in
Compose
In the buildingUI
Meeting how? - If we’re using a complex view
Compose
(e.g., useLazyColumn
replaceRecyclerViews
), but the root layout is still added inXML
In the - If we use
Compose
What about replacing elements of a page, rather than the entire page? - Whether it can be debugged and
R8
How much does the compiler affect performance?
To begin answering these questions, we built a simple test program. In the first version, we added a list of 50 elements (about 12 of which were actually drawn). The list includes a radio button and some random text.
To test the impact of various options, we added the following four configurations, all of which are enabledR8
It’s closed at the same timedebug
Pure Compose
- a
XML
In, with only oneComposeView
, the specific layout is written inCompose
In the XML
Contains only oneRecyclerView
, butRecyclerView
Each term of phi is oneComposeView
- pure
XML
To test the impact of build type on performance, the following three configurations were added
- pure
Compose
, close theR8
And open thedebug
- pure
Compose
, close theR8
And close thedebug
- pure
XML
, close theR8
And open thedebug
How do you define performance?
The Compose runtime performance is generally understood as the time between the page launching and the user seeing the content, so the following times are important for us
Activity
Startup time, i.eonCreate
Activity
Startup completion time, i.eonResume
Activity
The rendering completion time is the time the user sees the content
The timing of onCreate and onResume is easy to master by overriding the system methods, but how do you get the time when your Activity is fully drawn? We can add a ViewTreeObserver to the page root View and record the time of the last onDraw call
Using the Profile to view the process described above, the following is the process of rendering using XML versus composing, from OnCreate to the last call to onDraw
Rendering performance analysis
Now that we know how to define performance, can we start testing
- Each test ran on several devices, including the most recent flagship, No
Google Play
Service devices and some cheap cell phones. - Each test was run 10 times on the same phone, so we could get not only first render times, but also second render times
- test
Compose
Version for 1.0.0
We ran several times according to the configuration defined above, and got some data. Interested students can directly view all the data
As the results of the analysis are shown above, we can draw some conclusions
R8
And whether it can be debuggedJetpack Compose
Rendering time has a significant effect. In each experiment, disableR8
And debuggability enabled builds took more than twice as long as builds without them. On our slowest device,R8
Turns rendering speed up by more than half a second while disableddebug
Speed up rendering by half a second.XML
Contains only oneComposeView
Render time, with pureCompose
About the same amount of timeRecyclerView
Contains more than oneComposeView
It’s the slowest. This is not surprisingXML
The use ofComposeView
There is a cost, so it’s used in the pagesComposeView
Less is better.XML
In terms of presentationCompose
Faster. There is no way to solve this problem, and in each case,Compose
Render time ratioXML
Grow by about 33%.- The first startup always takes longer to render than subsequent launches. If you look at the full data, the rendering time of the first page is almost double that of the subsequent ones.
Somewhat to my surprise, although Compose does not have IO for converting XML to View and the measurement process is made more efficient by the inherent property measurement, the performance is still worse than that of XML. However, according to Leland Richardson, when installing an application from Google Play, Thanks to bundled AOT compilation, Compose renders faster at startup, further narrowing the gap with XML
conclusion
The above analysis of Compose performance is summarized as follows
- If you completely migrate to
Compose
In terms of package size, lines of code, compilation speed and so on, there should be a big improvement - If you are in a migration phase, you may introduce new dependencies instead of removing old ones, which may lead to larger packages
- Even though it’s gone
XML
The conversionIO
The operation, the measurement process is also optimized with intrinsic property measurements,Compose
Compared to the rendering performanceXML
There is still a gap - Despite the current
Compose
Slightly lacking in performance (just over a frame or two on most devices), but due to its impact on developer productivity, code reuse, and declarativeUI
The advantages of powerful features,Compose
Still recommended
The resources
Jetpack Compose — Before and after Measuring Render Performance with Jetpack Compose