Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Logic Based On Multiple Live Data Values

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.

like image 408
Josh Avatar asked Apr 29 '26 10:04

Josh


1 Answers

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

like image 127
Alex Avatar answered May 01 '26 23:05

Alex



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!