Am new to Android Development in general and especially with Jetpack Compose and its ways of updating the Composables. I have a iOS background with lots of SwiftUI though.
Anyways, I have the following app
The Composables look like this:
@Composable
fun Greeting() {
Column(
modifier = Modifier
.fillMaxHeight()2
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceEvenly
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
IncrementButton()
DecrementButton()
}
PressedText()
SizeText()
}
}
@Composable
fun PressedText() {
val myViewModel: MyViewModel = viewModel()
val myNumber by myViewModel.number.observeAsState()
Text(text = "Pressed: $myNumber")
}
@Composable
fun SizeText() {
val myViewModel: MyViewModel = viewModel()
val myList by myViewModel.list.observeAsState()
Text(text = "Size: ${myList?.size}")
}
@Composable
fun IncrementButton() {
val myViewModel: MyViewModel = viewModel()
Button(onClick = myViewModel::add) {
Text("Add")
}
}
@Composable
fun DecrementButton() {
val myViewModel: MyViewModel = viewModel()
Button(onClick = myViewModel::remove) {
Text("Remove")
}
}
The view model I am using looks like this:
class MyViewModel : ViewModel() {
private val _number = MutableLiveData<Int>()
val number: LiveData<Int> = _number
private val _list = MutableLiveData<MutableList<Int>>()
val list: LiveData<MutableList<Int>> = _list
init {
_number.value = 0
_list.value = mutableListOf()
}
fun add() {
_number.value = _number.value?.plus(1)
_number.value?.let {
_list.value?.add(it)
_list.value = _list.value
}
}
fun remove() {
_number.value = _number.value?.minus(1)
if (_list.value?.isNotEmpty() == true) {
_list.value?.removeAt(0)
_list.value = _list.value
}
}
}
When I press the "Add"-button the number after "Pressed" gets updated but not the number after "Size".
Am really not sure about those lines with _list.value = _list.value
that I have from some other SO post that said to update the reference of the list.
What am I missing? Any hints highly appreciated.
Feel free to leave any comments regarding code design.
Thank you!
CodePudding user response:
This _list.value = _list.value
is a really bad idea. Depending on underlying implementation, it may work or may not. In this case it's probably compared by pointer, that's why it doesn't trigger recomposition.
Check out Why is immutability important in functional programming.
The safe way is using non mutable list:
private val _list = MutableLiveData<List<Int>>()
And mutate it like this:
_list.value = _list.value?.toMutableList()?.apply {
add(value)
}
By doing this, you're creating a new list each time, and this will trigger recomposition without problems.
Also, using LiveData
is not required at all: if you don't have some dependencies, which makes you using it, you can go for Compose mutable state: it's much cleaner:
var number by mutableStateOf(0)
private set
private val _list = mutableStateListOf<Int>()
val list: List<Int> = _list
fun add() {
number
_list.add(number)
}
fun remove() {
number--
_list.removeAt(0)
}