Home > Software engineering >  ViewModel with LiveData and MutableList not Updating in Jetpack Compose
ViewModel with LiveData and MutableList not Updating in Jetpack Compose

Time:03-17

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

enter image description here

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)
}
  • Related