Home > Enterprise >  How to notify about state change if it is an instance of a class in jetpack compose
How to notify about state change if it is an instance of a class in jetpack compose

Time:03-13

I've got code like this:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            TestsTheme {
                var myvalue = remember{ mutableStateOf(4)}
                Row() {
                    CustomText(myvalue = myvalue)
                    CustomButton(myvalue = myvalue)
                }
            }
        }
    }
}

@Composable
fun CustomButton(myvalue: MutableState<Int>) {
    Button(onClick = {myvalue.value  }) {

    }
}

@Composable
fun CustomText(myvalue: MutableState<Int>) {
    Text("${myvalue.value}")
}

When I click CustomButton, CustomText recomposes and changes it's value (and it is ok), but if I replace myvalue with an object of some class it does'nt work

How do I make the CustomText recompose if myvalue is now an instance of TestClass and it changes in the code below?

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            TestsTheme {
                var myvalue = remember{ mutableStateOf(TestClass(4))}
                Row() {
                    CustomText(myvalue = myvalue)
                    CustomButton(myvalue = myvalue)
                }
            }
        }
    }
}

@Composable
fun CustomButton(myvalue: MutableState<TestClass>) {
    Button(onClick = {myvalue.value.a  }) {

    }
}

@Composable
fun CustomText(myvalue: MutableState<TestClass>) {
    Text("${myvalue.value.a}")
}

data class TestClass(var a: Int) {

}

CodePudding user response:

Compose can only understand that it should recompose if you set the value of a State object. In your example myvalue.value is really just short for myvalue.value = myvalue.value.inc(), so what triggers the recomposition is calling the state.value setter.
If you just mutate a property of the object held by a state, you are not calling the setter and no recomposition happens.

So you have 2 options to solve this:

  1. Make TestClass immutable and update the State with a new object
data class TestClass(val a: Int) { // << changed var to val

}

@Composable
fun CustomButton(myvalue: MutableState<TestClass>) {
    Button(onClick = {
        val current = myvalue.value
        myvalue.value = current.copy(a = current.a   1)
    }) {

    }
}

This is not really nice to read but doesn't require TestClass to contain any compose-specific code.

  1. Make TestClass a state holder
class TestClass(a: Int) { 
    var a by mutableStateOf(a)
}


@Composable
fun Parent(){
    val myvalue = remember{ TestClass(4) } // no mutableStateOf, state is managed inside the object
    CustomButton(myvalue = myvalue)
}
@Composable
fun CustomButton(myvalue: TestClass) {
    Button(onClick = { myvalue.a   }) {

    }
}
  • Related