In the io22 talk Performance best practices for Je...
# compose
s
In the io22 talk Performance best practices for Jetpack Compose, there is a

section

about Deferred reads and skipping compose phases. In particular there is a sample about animated background color and it is suggested to read color only inside
drawBehind
so that composition and layout phases can be skipped. I don't understand if composition is skipped, how snapshot subscription works and
drawBehind
is notified of color change. Is the draw phase executed on each frame? Is it related to nested use of composition for canvas?
Copy code
@Composable
fun SkipPhases() {
    val transition = rememberInfiniteTransition()
    val color by transition.animateColor(
        initialValue = Color.Cyan,
        targetValue = Color.Magenta,
        animationSpec = InfiniteRepeatableSpec(tween())
    )

    Box(modifier = Modifier.fillMaxSize().drawBehind { drawRect(color) }) {
        Text(text = "SkipPhases")
    }
}
j
Yes, draw is performed in each frame. This guide has a great explanation of the phases for compose and how they work and it's not too long of a read. https://developer.android.com/jetpack/compose/phases
👍 2
2
s
thanks. The document seems specifically written for this question!
y
That's a great article. I always considered canvas a special case with state reads in non composable drawscope being tracked. But this makes it clear canvas is just optimised component that skips compose and layout and only does custom draw phase.
💯 2
z
Draw doesn't actually happen on every frame, it happens any time the previous draw is invalidated. This happens when the bounds change or when a snapshot state object that was read in the previous draw changes. The functions you pass to the draw modifiers are executed with a snapshot observer that will invalidate that layer when a state changes. This is the same way that composition observes state, and also layout. Canvas isn't even really optimized, it's just hiding a few characters of boilerplate: https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Canvas.kt;l=42;drc=5995a24092b374267c17c7b82d529c3ca22f5cc5
mind blown 2
🧠 1
j
Yeah, I wasn’t very clear with that. I was thinking that Draw can occur in every frame and does occur where a recomposition occurs in that scope or like you said where state invalidates the draw scope specifically. Is that fair to say or is it possible for a recomposition to occur without draw being run for that scope?
z
Yep recomposition doesn’t automatically imply redraw. It also doesn't automatically imply layout.
👍 1
s
Yes I thought that @Joseph Hawkes-Cates means in this particular case of animated background it happens on each frame (which is correct AFAIK)