androidkotlinandroid-jetpack-composecompose-recompositionmutablestateof

Jetpack Compose: Surface makes state is persisting without remember


im currently experiencing with jetpack compose states.

Check out this composable:

@Composable
fun CounterWithoutRemember(reset: MutableState<Boolean>) {
    val count = mutableStateOf(0)

    Box(Modifier.fillMaxWidth()) {
        Column {
            Text("Your count: ${count.value}")
            ElevatedButton(onClick = {
                count.value += 1
            }) {
                Text("Add 1")
            }
        }
    }
}

This is working as expected. count is state without remember, that makes it resetting to 0 after recomposition.

But this code :

@Composable
fun CounterWithoutRemember(reset: MutableState<Boolean>) {
    val count = mutableStateOf(0)

    Surface(Modifier.fillMaxWidth()) {
        Column {
            Text("Your count: ${count.value}")
            ElevatedButton(onClick = {
                count.value += 1
            }) {
                Text("Add 1")
            }
        }
    }
}

I change the Box with Surface. with this code, i see that the count state is persisting like when i use remember when that composable recomposes. Can anyone explain me?

this is the activity :


class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val resetState = mutableStateOf(false)
        setContent {
            MyApplicationTheme {
                // A surface container using the 'background' color from the theme
                Surface(Modifier.padding(52.dp)) {
                    Column {
                        Counter()
                        CounterWithRemember(resetState)
                        CounterWithoutRemember(resetState)
                        ElevatedButton(onClick = {

                            resetState.value = !resetState.value

                        }) {
                            Text(text = "Reset")
                        }
                    }
                }

            }
        }
    }
}

Solution

  • Because Column, Row, and Box are inline functions and they don't create scopes, however Surface creates a scope as any other Composable that is not inline and returns Unit that limits composition range. Because of that CounterWithoutRemember is not recomposed.

    @Composable
    fun CounterWithoutRemember(reset: MutableState<Boolean>) {
        val count = mutableStateOf(0)
    
        Surface(Modifier.fillMaxWidth()) {
            Column {
                Text("Your count: ${count.value}")
                ElevatedButton(onClick = {
                    count.value += 1
                }) {
                    Text("Add 1")
                }
            }
        }
    }
    

    Why does mutableStateOf without remember work sometimes?