theapache64
08/21/2021, 5:14 PMrememberUpdateState? π€ Maybe βwith and without rememberUpdateState βAlex Gabor
08/21/2021, 5:24 PMonReceive it should call currentOnSystemEvent instead of onSystemEvent.Alex Gabor
08/21/2021, 5:28 PMrememberUpdatedState should be used because the parameter onSystemEvent can change after recomposition and you want the BroadcastReceiver to use the latest value without recreating it on recompositiontheapache64
08/21/2021, 5:32 PMrememberUpdateState , but what I canβt understand is βhow would be the behaviour without itβ.
for eg. hereβs a sample from official docs.
Code A (official)
@Composable
fun LandingScreen(onTimeout: () -> Unit) {
val currentOnTimeout by rememberUpdatedState(onTimeout)
LaunchedEffect(true) {
delay(SplashWaitTimeMillis)
currentOnTimeout()
}
}
Code B
@Composable
fun LandingScreen(onTimeout: () -> Unit) {
LaunchedEffect(true) {
delay(SplashWaitTimeMillis)
onTimeout()
}
}
both A and B produce the same output even if the LandingScreen recomposed more than one time, right?Aditya Wasan
08/21/2021, 5:33 PMtheapache64
08/21/2021, 5:34 PMAditya Wasan
08/21/2021, 5:34 PMDoris Liu
08/21/2021, 5:34 PMLaunchedEffect does an implicit capture of the onTimeOut lambda. Without the rememberUpdatedState, it'll be invoking the potentially outdated lambda.Aditya Wasan
08/21/2021, 5:35 PMHalil Ozercan
08/21/2021, 5:35 PMDoris Liu
08/21/2021, 5:37 PMtheapache64
08/21/2021, 5:38 PMonTimeout changed during the delay ?Doris Liu
08/21/2021, 5:40 PMtheapache64
08/21/2021, 5:43 PMrememberUpdatedState that produce different output for each πAditya Wasan
08/21/2021, 5:43 PMHalil Ozercan
08/21/2021, 5:44 PMfun main() = singleWindowApplication {
Top()
}
@Composable
fun Top() {
val counter by produceState(0) {
while(isActive) {
delay(10)
value += 1
}
}
val myLambda: () -> Unit = if (counter % 2 == 0) {
{ println("This is even: $counter") }
} else {
{ println("This is odd: $counter") }
}
Child(myLambda)
}
@Composable
fun Child(block: () -> Unit) {
LaunchedEffect(Unit) {
while (isActive) {
delay(100)
block.invoke()
}
}
}Halil Ozercan
08/21/2021, 5:45 PMThis is even: 4
This is even: 12
This is even: 22
This is even: 29
This is even: 39
This is even: 48
This is even: 58
This is even: 67
This is even: 77
This is even: 87
This is even: 97Halil Ozercan
08/21/2021, 5:45 PMHalil Ozercan
08/21/2021, 5:46 PMrememberUpdatedState , these are the logs
This is odd: 3
This is even: 12
This is even: 22
This is even: 32
This is even: 42
This is even: 52
This is odd: 61
This is odd: 71
This is odd: 81
This is odd: 91
This is odd: 101
This is odd: 111Doris Liu
08/21/2021, 5:47 PMHalil Ozercan
08/21/2021, 5:50 PMHalil Ozercan
08/21/2021, 5:51 PMRafs
08/21/2021, 5:52 PMLandingScreen demo where the lambda is never changed without the rememberUpdatedState call. Thanks @Halil Ozercan I think i'm getting the hang of it now.
val SplashWaitTimeMillis = 5000L
@Composable
fun RememberUpdatedState() {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
var callback by remember {
mutableStateOf({
println("Hello from initial callback")
})
}
LaunchedEffect(Unit) {
delay(2000)
callback = {
println("Hello from new callback")
}
}
LandingScreen(callback)
}
}
@Composable
fun LandingScreen(onTimeout: () -> Unit) {
// This will always refer to the latest onTimeout function that
// LandingScreen was recomposed with
val currentOnTimeout by rememberUpdatedState(onTimeout)
// Create an effect that matches the lifecycle of LandingScreen.
// If LandingScreen recomposes, the delay shouldn't start again.
LaunchedEffect(true) {
delay(SplashWaitTimeMillis)
currentOnTimeout()
}
/* Landing screen content */
}Doris Liu
08/21/2021, 5:54 PMval textToDisplay = counter.toString()
val myLambda: () -> Unit = { textToDisplay }
Child(myLambda)Aditya Wasan
08/21/2021, 5:56 PMDoris Liu
08/21/2021, 6:01 PMtheapache64
08/21/2021, 6:02 PMHalil Ozercan
08/24/2021, 2:42 PMrememberUpdatedState . It's rather complicated but I'll try to simplify it as much as I can:
β’ Inline content composables in a Text needs to get their constraints before the whole text is measured.
β’ We pass these constraints using a lambda with a signature of () -> Constraints .
β’ This has never been a problem because constraints for text almost never change in Android. Even if they do, inline content is rarely used.
β’ Image is an inline content. Desktop windows are easily resizable. Images never get the updated constraints because lambda goes stale
β’ Adding rememberUpdatedState solves this problem.Halil Ozercan
08/24/2021, 2:46 PMHalil Ozercan
08/24/2021, 2:47 PMrememberUpdatedStatetheapache64
08/24/2021, 4:31 PMKefas
08/24/2021, 5:21 PM@Composable
fun Screen() {
var number by remember { mutableStateOf(0) }
LaunchedEffect(Unit) {
delay(100L)
number = 1
}
Foo(number)
}
@Composable
fun Foo(number: Int) {
println("Recomposed with $number")
val currentNumber = number
Text(text = "$currentNumber")
LaunchedEffect(Unit) {
println("Start effect")
delay(200L)
println("currentNumber = $currentNumber")
}
}
Result:
Recomposed with 0
Start effect
Recomposed with 1
currentNumber = 0
I still don't get it.
β’ Why the Text can get the latest value whereas the effect can't?
β’ If I use rememberUpdatedState instead, the effect can get the latest value. Why is that? Isn't the value itself already a state?Halil Ozercan
08/24/2021, 5:55 PMnumber is a state in Screen composable and when it changes, compose runtime knows exactly where to update. However, Effects are scheduled when composition happens for the first time. As your effect never gets invalidated, it has a stale version of number which is currentNumber. currentNumber is not a state in the Foo composable. It resets at each recomposition but those recompositions doesn't really change anything for the scheduled LaunchedEffect . Once that LaunchedEffect runs, it reads the value from first composition.
On the other hand, when you use rememberUpdatedState , number becomes a state in Foo composable context. Any effect that is scheduled from Foo will read the correct state value when it's accessed.Halil Ozercan
08/24/2021, 5:56 PMFoo composable and read the currentNumber as state.value ?Kefas
08/24/2021, 5:59 PMsend a State<Int> to@Halil Ozercan The result is 1 (the latest value)composable and read the currentNumber asFoo?state.value
Halil Ozercan
08/24/2021, 6:01 PMKefas
08/24/2021, 6:11 PMState objects are passed into parameters instead of its value.Halil Ozercan
08/24/2021, 6:13 PM