Reputation: 956
I am using the Android data binding library to make reactive views with LiveData
I make a repo request for a list of jobs
var jobsRequest: LiveData<Resource<List<Job>>>
= Transformations.switchMap(position) { repo.getJobsWithStatus(it) }
Then I have 3 more LiveData based on the above, like so
First, to check whether the request has completed
private val requestComplete: LiveData<Boolean>
= Transformations.map(jobsRequest) {
it.status == Status.SUCCESS || it.status == Status.ERROR
}
Next, to transform to a list of jobs without the resource wrapper
var jobs: LiveData<List<Job>>
= Transformations.map(jobsRequest) { it.data }
Lastly, to check if that job list is empty
val jobsEmpty: LiveData<Boolean>
= Transformations.map(jobs) { (it ?: emptyList()).isEmpty() }
In the layout I want to show a loading spinner if the request has not completed and the jobs list is empty and need a variable in my view model to dictate this
I have tried the code below and, as expected, it does not work
val spinnerVisible: LiveData<Boolean>
= Transformations.map(requestComplete) {
!(requestComplete.value ?: false) && (jobsEmpty.value ?: true)
}
What is the correct practice for having a LiveData variable based on the state of 2 others - I want to keep all logic in the view model, not in the activity or layout.
Upvotes: 3
Views: 2804
Reputation: 1730
Is the jobsEmpty
observer needed? Seems like you could reuse the jobs
one for it.
Anway, to your question:
For this there is a MediatorLiveData
. It does what you need: it can merge multiple (in your case: 2) LiveData objects and can determine another livedata value based on that.
Some pseudo-code:
MediatorLiveData showSpinner = new MediatorLiveData<Boolean>()
showSpinner.addSource(jobsEmpty, { isEmpty ->
if (isEmpty == true || requestComplete.value == true) {
// We should show!
showSpinner.value = true
}
// Remove observer again
showSpinner.removeSource(jobsEmpty);
})
showSpinner.addSource(requestComplete, { isCompleted ->
if (isCompleted == true && jobsEmpty == true) {
// We should show!
showSpinner.value = true
}
// Remove observer again
showSpinner.removeSource(requestComplete);
})
return showSpinner
Note that you need to return the mediatorlivedata as result, as this is the object you are interested in for your layout.
Additionally, you can check the documentation on the MediatorLiveData
, it has some more examples: https://developer.android.com/reference/android/arch/lifecycle/MediatorLiveData
Upvotes: 1