Reputation: 5057
I have this ViewModel
that gets a list from the network and I populate a RecyclerView
with the data (MyAvailabilityRepository
returns a MutableLiveData
, that's why i'm using Transformations.switchMap
):
class MyAvailabilityViewModel : ViewModel() {
private val getListsParams = MutableLiveData<String>()
private val getListsObservable = Transformations.switchMap(getListsParams) {
organizationId -> MyAvailabilityRepository.getSectionedLists(organizationId)
}
fun getListsObservable() : LiveData<Resource<MutableList<SectionedAvailabilityList>>> {
return getListsObservable
}
fun fetchLists(organizationId: String, forceRefresh: Boolean = false) {
if (getListsParams.value == null || forceRefresh) {
getListsParams.value = organizationId
}
}
}
Fragment's onActivityCreated
:
override fun onActivityCreated(savedInstanceState: Bundle?) {
...
viewModel.getListsObservable().observe(this, Observer { // populate RecyclerView })
viewModel.fetchLists(organizationId)
}
Since getListParams.value
is null the first time, it will set getListsParams.value = organizationId
and trigger the switchMap
and call the repository to get the list from the network.
When I want to force a refresh (by pull-to-refresh) and call the network again, I can use forceRefresh = true
:
override fun onRefresh() {
viewModel.fetchLists(organizationId, forceRefresh = true)
}
It will set the value of organizationId
and trigger the Transformations that will then call network.
But, I have a scenario where I clear the data from my RecyclerView's adapter. If after that, the user click a button, I would like to trigger the observer again so that I re-populate the adapter with the data that the getListsObservable has already fetched. I don't want to call forceRefresh on this one cause i'm sure I already have the data and I would just like to trigger the observer again so that my UI is updated with the existing data. Since getListParams.value
is not null at that point, then nothing happens when I call fetchLists(organizationId)
later on.
Any idea of how I could achieve that with my current setup?
Upvotes: 18
Views: 8611
Reputation: 6938
I do force refresh by this approach -
if (mainViewModel.mutable != null && mainViewModel.mutable.getValue()) {
mainViewModel.mutable.setValue(mainViewModel.mutable.getValue());
}
Upvotes: 1
Reputation: 798
Yes, the answer given by Hong Duan is perfect. I am just going to extend that answer here,
The better way of doing is having an extension function.
My extension function looks like this,
fun <T> MutableLiveData<T>.forceRefresh() {
this.value = this.value
}
Caller function looks like this,
mutableLiveDataObject.forceRefresh()
Happy Coding!!
Upvotes: 30
Reputation: 4294
Try removeObservers()
and observe()
again:
viewModel.getListsObservable().removeObservers(this)
viewModel.getListsObservable().observe(this, Observer { // populate RecyclerView })
because:
If LiveData already has data set, it will be delivered to the observer.
See the docs.
Or maybe you can change the getListsObservable()
to return a MutableLiveData
, then call setValue
manually:
fun loadCurrentData() {
getListsObservable.value = getListsObservable.value
}
Upvotes: 5