Hey guys, I was looking at the `MaterialTheme` obj...
# compose-android
m
Hey guys, I was looking at the
MaterialTheme
object and also its composable function. Something caught my attention. I don't understand why they are creating a
copy
of the
colorScheme
and then call the
updateColorSchemeFrom
extension function again. I think they are the same. Am I missing something here? https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/[…]ialTheme.kt;drc=bcaacc85477f959cac171b60258679b6244f512b;l=69
Copy code
@Composable
fun MaterialTheme(
    colorScheme: ColorScheme = MaterialTheme.colorScheme,
    shapes: Shapes = MaterialTheme.shapes,
    typography: Typography = MaterialTheme.typography,
    content: @Composable () -> Unit
) {
    val rememberedColorScheme = remember {
        colorScheme.copy()
    }.apply {
        updateColorSchemeFrom(colorScheme) // This function also copy the values from colorScheme just like the copy function called inside the remember block.
    }
    val rippleIndication = rememberRipple()
    val selectionColors = rememberTextSelectionColors(rememberedColorScheme)
    CompositionLocalProvider(
        LocalColorScheme provides rememberedColorScheme,
        LocalIndication provides rippleIndication,
        LocalRippleTheme provides MaterialRippleTheme,
        LocalShapes provides shapes,
        LocalTextSelectionColors provides selectionColors,
        LocalTypography provides typography,
    ) {
        ProvideTextStyle(value = typography.bodyLarge, content = content)
    }
}
s
They are doing this so that they do not create a new object each time. Instead they create the copy once, and from that point on, on every recomposition if the
colorScheme
changes, then the resulting colorScheme will have all of its internal values (which are MutableState objects) will be updated accordingly, and since they are state as I said before, all the composable functions that read them will recompose appropriately. So I think tl;dr of this is that it’s an optimization, not for correctness. That’s my understanding
m
I'm not sure if I understand the point. My question is, why do they make two copy of the
colorScheme
? First, inside the remember block, and then inside the apply block. 🤔
s
The apply block will run on each recomposition, the block inside the remember will only run on first composition. And as far as the first composition goes, yes both will run, but I assume
updateColorSchemeFrom
when provided with the exact same colors (which it always is the case on first composition) will be a no-op, so it doesn’t matter.
m
So if I understand it well, they first make a copy of the
ColorScheme
in the first composition. Then, on each recomposition, they just update the properties. Am I right?
s
Yeah, every recomposition,
updateColorSchemeFrom
is called again, since it’s just part of the composable itself, not inside a lambda or some other side-effect composable. It just happens every single recomposition. It’s more or less the same as if they wrote this
Copy code
SideEffect {
  rememberedColorScheme.updateColorSchemeFrom(colorScheme)
}
And they must be relying on the fact that
updateColorSchemeFrom
shouldn’t be expensive if the same colorScheme is passed in there over and over again.
Ah and it does seem like all it does is set some compose state objects https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:tv/tv-ma[…]ColorSchemeFrom&ss=androidx%2Fplatform%2Fframeworks%2Fsupport So if the object is equivalent, this simply does nothing, no recompositions happen, it just skips that change.
m
Yes I just saw that. Now I think I know it by heart. I just read about the difference between
remember
and
rememberUpdatedState
and I finally got the point. Thank u very much 👍 https://stackoverflow.com/a/70223293 https://proandroiddev.com/jetpack-compose-side-effects-iii-rememberupdatedstate-c8df7b90a01d
👍 1