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(...))