Home > Blockchain >  Jetpack Compose recomposition race condition
Jetpack Compose recomposition race condition

Time:10-29

Suppose we have the following code. It displays a button, and when the user clicks on it, the button disappears.

@Composable
fun ButtonThatDisappearsOnClick() {
    var showButton by remember { mutableStateOf(true) }
    if (showButton) {
        Button(onClick = {
            check(showButton) { "onClick shouldn't be called for a hidden button" }  // !!!
            showButton = false
        }) {
            Text("My button")
        }
    }
}

I suspect that the check call above may fail if the user clicks the button twice really quickly:

  • The user clicks the button, shouldShowButton is set to false. Since the value in a mutable state was updated, a recomposition is scheduled.
  • The user clicks the button very quickly again before the views have been recomposed. Thus, the onClick function will fire the second time, and the check call will fail.

I have not been able to reproduce this in practice, so I am wondering if such a behavior is indeed possible.

CodePudding user response:

It is possible. Unlikely to happen, but possible. In practice, fast click or double click problem is present in compose. In this particular case this can happen because the example composable is holding some kind of state.

There is a practice of making composable stateless and keeping states outside. Compose will be able to detect parameter changes outside particular recomposition flow and possibly cancel it. (In your case, it won't hide the button and therefore you won't reach the unexpected behavior)

From official documentation

Recomposition starts whenever Compose thinks that the parameters of a composable might have changed. Recomposition is optimistic, which means Compose expects to finish recomposition before the parameters change again. If a parameter does change before recomposition finishes, Compose might cancel the recomposition and restart it with the new parameter.

CodePudding user response:

This question is answer what you ask for. Op changes values consecutively but if state value changes before recomposition is completed it's a possibility that previous recomposition is discarded and new one is scheduled.

MutableState ignores first value if set two values in a row

SideEffect function can be used for operations that should be invoked only when a successful recomposition happens

Recomposition starts whenever Compose thinks that the parameters of a composable might have changed. Recomposition is optimistic, which means Compose expects to finish recomposition before the parameters change again. If a parameter does change before recomposition finishes, Compose might cancel the recomposition and restart it with the new parameter.

When recomposition is canceled, Compose discards the UI tree from the recomposition. If you have any side-effects that depend on the UI being displayed, the side-effect will be applied even if composition is canceled. This can lead to inconsistent app state.

Ensure that all composable functions and lambdas are idempotent and side-effect free to handle optimistic recomposition.

  • Related