Home > database >  Why does my observer doesn't get notified when a new item is added to my livedata list
Why does my observer doesn't get notified when a new item is added to my livedata list

Time:08-20

I need to get an Observer event when the item is added to the List of LiveData.

// mutable live data list of shoes
private var _shoesList =  MutableLiveData<List<Shoe>>()
val shoesList: LiveData<List<Shoe>>
    get() = _shoesList

When I add a new item to the list

_shoesList.value?.plus(Shoe(name,sizeDouble,company,description))
        _shoesList.value = _shoesList.value // so the observer gets notified

The observer code:

 val viewModel = ViewModelProvider(this).get(MainActivityViewModel::class.java)

The code inside the observer block is never reached

viewModel.shoesList.observe( viewLifecycleOwner , Observer { newShoe ->

                Log.i("ShoeListFragment","i am inside the observer block")

        })

I am still a beginner so any help would be apprciated :)

CodePudding user response:

plus returns a new list which is the original list with your new Shoe added to it - it doesn't affect the original list. plusAssign adds to the original.

Those are both operator functions (see the operator keyword) which means you can use them like:

// plus
shoesList   newShoe

// plusAssign
shoesList  = newShoe

If you're not familiar with =, the longer version is shoesList = shoesList newShoe. So you can tell you're reassigning the value of shoesList with that one. Just doing shoesList newShoe doesn't change anything - you just combine them and then do nothing with the result.

But your LiveData holds an immutable List type, not a MutableList - so you can't add to that. You can't use plusAssign here, you need to use plus to create a new list (the original combined with the new element) and then assign it to your LiveData:

// store the result of your plus call
val newShoes = _shoesList.value?.plus(Shoe(name,sizeDouble,company,description))
_shoesList.value = newShoes // you need to assign the new list anyway!

So not much of a change from what you already had, but hopefully that gives you a better idea of what's going on! If you were using a MutableList, you could just do plusAssign, but yeah you'd have to reassign the value to nudge it into updating its observers.

And honestly, creating a new list is usually safer, because you're not modifying the original one, which other things might have stored a reference to. For example, if you're using a DiffUtil in a RecyclerView, which compares the old list to a new one... if you change the old one and then push that as the new one, the DiffUtil is looking at two references to the same object. So there's no difference, meaning it doesn't trigger an update (the old list did change, but all it can do is compare to the new one, which is the same list). You can get other bugs changing old data in the background like that, while outwardly pushing a "new" value

CodePudding user response:

MutableLiveData contains a list of shoes, you need to declare them separately in your view model:

private var _shoes = mutableListOf<Shoe>()
private var _shoesList =  MutableLiveData<List<Shoe>>(_shoes)

And expose LiveData to anyone who wants to listen to data changes:

val shoesList: LiveData<List<Shoe>>
        get() = _shoesList

whenever you want to add a new Shoe, just add it in the _shoes list

_show.add(new Shoe(..))

And then update the mutableLiveData to notify listener :

//notify observers
_shoesList.postValue(_shoes)

_shoes is a private variable, add this method to be able to add a new shoe:

fun add(shoe: Shoe) = viewModelScope.launch {
    _shoes.add(shoe)

    //notify observer
    _shoesList.postValue(_shoes)
}

Here is the complete code :

class ShoeViewModel() : ViewModel() {

    private var _shoes = mutableListOf<Shoe>()
    private var _shoesList =  MutableLiveData<List<Shoe>>(_shoes)

    val shoesList: LiveData<List<Shoe>>
        get() = _shoesList

    fun add(shoe: Shoe) = viewModelScope.launch {
        _shoes.add(shoe)

        //notify observer
        _shoesList.postValue(_shoes)
    }
}

call this line of code, every time you want to add a new shoe

viewModel.add(new Shoe(...)) 
  • Related