https://kotlinlang.org logo
Title
t

Tgo1014

05/18/2023, 1:08 PM
Why A works and B doesn't? Isn't
remember
just to keep the value across recompositions?
mutableStateOf
is not enough to trigger recompositions?
@Composable
@Preview
fun Test() {
    var a by remember { mutableStateOf(false) }
    var b by mutableStateOf(false)
    val c by derivedStateOf { a && b }
    Column {
        Text(text = "A $a")
        Text(text = "B $b")
        Text(text = "C $c")
        Button(onClick = { a = !a }) {
            Text("A")
        }
        Button(onClick = { b = !b }) {
            Text("B")
        }
    }
}
m

mikehearn

05/18/2023, 1:10 PM
Every time the Test function is recomposed (re-executed)
b
will be recreated from scratch
You need
remember{}
to stop that happening and ensure the object persists even across re-executions of the function. Yeah it's a bit weird. Think of the function as if it's a class and
remember{}
as if it's a property, if that helps. Then you can see that
b
will be just a normal local variable.
t

Tgo1014

05/18/2023, 1:11 PM
But
b
is a object that keep the value, no? So if I do
b = !b
why it goes back to false? I don't think the entire screen is being recreated, no?
k

krzysztof

05/18/2023, 1:20 PM
Calling
b = !b
, will recompose
Test()
again. This is because the
Column
is inlined, so that the recomposition scope goes up to
Test
itself. And calling
Test
itself will create a new member variable
b
with
false
value
m

mikehearn

05/18/2023, 1:29 PM
"Composition" is a fancy term for re-execution. Every time anything changes in your UI, conceptually, the entire code from
application{}
or
setContent{}
on down is re-executed fresh. The only way to preserve data is either use global variables or use
remember
.
b
is not an object that keeps its value. A
MutableState
is just an observable variable with fancy extras. It can trigger event handlers when it changes, but it has nothing to say about how long it lasts in the heap. It's no different to allocating any other object as a local variable.
t

Tgo1014

05/18/2023, 1:33 PM
I thought when you changed
b
it would just recompose what's using the value of
b
🤔
k

krzysztof

05/18/2023, 1:34 PM
Because that’s true.
the entire code from
application{}
or
setContent{}
on down is re-executed fresh.
is wrong statement in that regards and would be super duper inefficient to have in any ui framework
t

Tgo1014

05/18/2023, 1:35 PM
Ok, so it's as I imagined, the
Test()
is not recomposed, so why would the value be lost? That's the bit I'm missing
k

krzysztof

05/18/2023, 1:36 PM
In your example, like I said, your Test would be recomposed as whole, because the the
b
value is read in a scope of it
If you do this:
Column {
        Text(text = "A $a")
//        Text(text = "B $b")
        Text(text = "C $c")
        Button(onClick = { a = !a }) {
            Text("A")
        }
        Button(onClick = { b = !b }) {
            Text("B ${b}") // note here
        }
    }
Then your
b
will keep the value, until
a
is changed.
that’s because of recomposition scope, where
b
is no longer read within
Test
scope, but rather in Button’s
content
scope.
a
is still read within
Test
scope, so if that changes, compose calls
Test
function again
t

Tgo1014

05/18/2023, 1:41 PM
So basically anytime a
State
changes, Compose will retrigger everything from the earliest access point of the
State
?
k

krzysztof

05/18/2023, 1:42 PM
Yes, exactly. The point to know is that Compose function creates recomposition scope, so if any Snapshot value (which is data holder created by
mutableStateOf
) is read within that scope, compose will re-run that composable if that value changes
I can suggest this article by Vinay, which is great in explaining this part https://www.jetpackcompose.app/articles/donut-hole-skipping-in-jetpack-compose
t

Tgo1014

05/18/2023, 1:44 PM
Thanks @krzysztof super helpful. I'll read the article 😄
k

krzysztof

05/18/2023, 1:45 PM
you’re welcome, good luck!
m

mikehearn

05/18/2023, 1:53 PM
Yes, that's why I said "conceptually". It'll only re-execute parts, but that's an optimization.