1

Please see my code:

@Composable
fun RecomposeLambdaTest() {
    var state by remember {
        mutableStateOf("1")
    }

    val stateHolder = remember {
        StateHolder()
    }
    Column {
        Button(onClick = {
            state += "1"
        }) {
            Text(text = "change the state")
        }
        OuterComposable(state = state) {
            stateHolder// just a reference to the instance outer the scope
        }
    }
}

@Composable
fun OuterComposable(state: String, onClick: () -> Unit) {
    LogUtil.d("lambda hashcode: ${onClick.hashCode()}")

    Column {
        Text(text = state)

        Button(onClick = onClick) {
            Log.d("Jeck", "compose 2")
            Text(text = "Text")
        }
    }
}

//@Stable
class StateHolder{
    private var b  = 2
}

Every time I click button, OuterComposable recompose, and log the lambda hashcode——always different! It means that a new lambda instance is created when recompose, everytime

and I uncomment the code in StateHolder and make it look like:

@Stable
class StateHolder{
    private var b  = 2
}

Every time I click button, OuterComposable recompose, and log the lambda hashcode——always the same! It means that when recompose, Composer reuse the lambda

So what' s under the hood?

Edit: Ok, make it easier, Let's change the code like this:

val stateHolder = remember {
        2
}

the result is lambda is reused. make val to var, the lambda is created when every recompose.

So I think I know that: If the lambda refenence a valuable outer scope and the valuable is not stable, recreate lambda every time.

So the question is:

  1. Why Compose compiler do this?
  2. Why Compiler think the StateHolder before is not stable, it only contains a private var!?
Halil Ozel
  • 2,482
  • 3
  • 17
  • 32
JeckOnly
  • 347
  • 2
  • 10
  • you are printing the hash of the lambda – zjmo Nov 08 '22 at 15:49
  • @zjmo could you explain it in detail, do you think the lambda is not a new instance? – JeckOnly Nov 11 '22 at 13:46
  • ah yes I misunderstood. Probably is because compose cannot understand if stateHolder is referencing the same object. What happen if you wrap StateHolder instance in a mutableStateOf()? – zjmo Nov 11 '22 at 14:22
  • 2
    I'm having a hint why this is happening, but still not able to grasp it fully, what your'e trying to do here might be explained by this article of [Ben Trengrove](https://stackoverflow.com/users/616971/ben-trengrove) that I got from a fellow S.O [@Stable/@Immutable](https://medium.com/androiddevelopers/jetpack-compose-stability-explained-79c10db270c8) – z.g.y Nov 15 '22 at 09:39

2 Answers2

1

An author met the same question, here is his article——6 Jetpack Compose Guidelines to Optimize Your App Performance

He said, private property still affact stability, it seems it is a Google team's choice.

JeckOnly
  • 347
  • 2
  • 10
0
class StateHolder{
   private var b  = 2
}

In this class b variable is mutable and any mutable variable makes the class unstable. So when recompose compose this this value will be changed as this is var.

Check this doc for details

Shaon
  • 2,496
  • 26
  • 27