I have an Android viewmodel for a Fragment that requires the user to perform multiple tasks. In addition to a LiveData
object to track the status of each task, I also need a LiveData
that tracks a summary of the status of all the tasks.
I wrote the following MediatorLiveData
class that takes a list of LiveData
objects and watches them all for changes, then applies a given function to compute the summary each time a value changes:
class ListOfLiveData<T, E>(
private val sources: List<LiveData<T>>,
private val evaluator: (List<LiveData<T>>) -> E
) : MediatorLiveData<E>() {
init {
sources.forEach {
addSource(it) { value = evaluator(sources) }
}
}
}
Here is how I am using it right now:
class TaskViewModel : ViewModel() {
// Can be DENIED, UNKNOWN, or GRANTED for each one
private val _phoneStatus = MutableLiveData(Status.UNKNOWN)
private val _locationStatus = MutableLiveData(Status.UNKNOWN)
private val _videoStatus = MutableLiveData(Status.UNKNOWN)
private val _audioStatus = MutableLiveData(Status.UNKNOWN)
val phoneStatus: LiveData<Status> = _phoneStatus
val locationStatus: LiveData<Status> = _locationStatus
val videoStatus: LiveData<Status> = _videoStatus
val audioStatus: LiveData<Status> = _audioStatus
val allStatus = ListOfLiveData<Status, Status>(
listOf(
_phoneStatus,
_locationStatus,
_videoStatus,
_audioStatus,
)
) {
// If any individual task status is DENIED or UNKNOWN, return that value.
// Otherwise, they must all be GRANTED
it.forEach { p ->
if (p.value == Status.DENIED) {
return@ListOfLiveData Status.DENIED
}
if (p.value == Status.UNKNOWN) {
return@ListOfLiveData Status.UNKNOWN
}
}
return@ListOfLiveData Status.GRANTED
}
}
(In this example the source types and the return type are the same, but I can think of other places in the app that it would be useful to have a different return type.)
Is this a good design?
Is there anything built into the framework that would have already done this?
Am I missing anything important?