

Compose phases and optimizations
source link: https://www.valueof.io/blog/compose-phases-optimizing-composition-layout-drawing
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

May 13, 2022

There is an excellent talk from Google I/O 2022 titled Performance best practices for Jetpack Compose. A part of it includes an example of a potential optimization related to Compose phases. This blog post is meant to spread that knowledge using a different medium.
Jetpack Compose phases
Compose renders each frame through 3 distinct phases:

Composition: determines what the user interface should look like based on composable functions in your UI tree.
Layout: Measures user interface widgets and decides where to place them on the screen. Modifiers and composables from the Composition phase are taken into account to complete this phase.
Drawing: Draws the user interface elements to the screen based on measurements provided by the Layout phase.
For more details, on Compose Phases, see https://developer.android.com/jetpack/compose/phases
These 3 phases are repeated for every frame and each phase uses computing power. There are instances where performance can be improved by skipping one or more Compose phases. Let’s look at a practical easy to digest example below.
Inline with the Google I/O example, let’s create a simple 200x200 square and repeatedly animate its color between initialValue
to targetValue
and back.
@Composable fun MyBox() { val color by animateColorBetween(Color.Red, Color.Green) Box( modifier = Modifier .wrapContentSize(Alignment.Center) .width(200.dp) .height(200.dp) .background(color) ) { println("Recomposing") } } @Composable private fun animateColorBetween( initialValue: Color, targetValue: Color ): State<Color> { val infiniteTransition = rememberInfiniteTransition() return infiniteTransition.animateColor( initialValue = initialValue, targetValue = targetValue, animationSpec = infiniteRepeatable( animation = tween(2000), repeatMode = RepeatMode.Reverse ) ) }
Which will result in the following UI:

The problem with the code above is that every time a color changes (on every frame!), our Box
will recompose. Notice the println(“Recomposing”)
in the content lambda. When the UI renders, the Logcat will update repeatedly:
20:30:35.282 18878-18878/com.example.demo I/System.out: Recomposing 20:30:35.300 18878-18878/com.example.demo I/System.out: Recomposing 20:30:35.321 18878-18878/com.example.demo I/System.out: Recomposing 20:30:35.336 18878-18878/com.example.demo I/System.out: Recomposing
Skipping phases for better performance
Since the only thing that changes on every frame is our Box color, we should be able to redraw the Box using Draw phase and not repeat the Composition and Layout phases every time the color changes.
To do that, we can explicitly ask for Draw phase every time color changes:

To do that, we change our Modifier
to draw on Canvas with help of lambda-based modifier drawBehind
:
@Composable fun MyBox() { val color by animateColorBetween(Color.Red, Color.Green) Box( modifier = Modifier .wrapContentSize(Alignment.Center) .width(200.dp) .height(200.dp) .drawBehind { drawRect(color) } ) { println("Recomposing") } }
Instead of using .background
we use .drawBenind
that accesses DrawScope
directly whenever color changes. Therefore, only the Draw
phase gets re-executed when color changes.
For more detailed post on drawing on Canvas, see my post Getting started with Canvas in Compose.
Our UI won’t change but rendering is now more efficient—the Composition andtherefore Layout phases only happened once as evident by the Logcat. Only the Draw
phase needed to be repeated.
20:43:04.570 19244-19244/demo I/System.out: Recomposing
fun drawRect
is a function instance (not a composable function) that reads the color state. The function instance itself does not change and therefore does not require re-composition or a new layout path.
Further reading
Recommend
-
8
There is more to running an open source project than writing code. In fact most of all work has to do with something else. This places additional requirements to project maintainers that are often not talked about. In this post we'll briefly...
-
4
Design Processes, Implementation Phases and Creating an MVPThe topic of MVPs recently came about in a discussion with fellow Designers and former co-workers. Our discussion was prompted by the qu...
-
17
Last time we were talking about the most common Migration strategies for Cloud Providers (Repurchasing, Rehosting, and Relocating), and migration types (Hot, Warm and Cold)...
-
18
Software Development Life Cycle, Phases, Methodologies & Practices Explained!April 20th 2021 new story6
-
13
Kevin Healy: Craig Wright went through 3 phases of being Satoshi Nakamoto Interviews 8 hours ago...
-
4
Research Recap: Five Phases for Creating Powerful Personas
-
9
Local Google My Business phases out short names If your business currently uses short names, the links and c...
-
22
The clinical trial is a human medical study designed to test the safety and effectiveness of drugs, therapeutic products and devices before they are ultimately launched in the market. Around the world, the market is witnessing significant growth...
-
8
Like most other UI toolkits, Compose renders a frame through several distinct phases. If we look at the Android View system, it has three main phases: measure, layout, and drawing. Compose is very similar but has an important additio...
-
10
SAP Activate Elements and Phases SAP Activate guideline framework helps customers to move/migrate legacy system to S4HANA system by providing various general and solution specific roadmaps under roadmap viewer.
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK