Reputation: 11999
I am using the liveData coroutine as follows. My function takes 3 params - accessing database, make a API call and return the API result
fun <T, A> performGetOperation(
databaseQuery: () -> LiveData<T>,
networkCall: suspend () -> Resource<A>,
saveCallResult: suspend (A) -> Unit
): LiveData<Resource<T>> =
liveData(Dispatchers.IO) {
emit(Resource.loading())
val source = databaseQuery.invoke().map { Resource.success(it) }
emitSource(source)
val responseStatus = networkCall.invoke()
if (responseStatus.status == SUCCESS) {
saveCallResult(responseStatus.data!!)
} else if (responseStatus.status == ERROR) {
emit(Resource.error(responseStatus.message!!))
emitSource(source)
}
}
I am calling the function as
fun getImages(term: String) = performGetOperation(
databaseQuery = {
localDataSource.getAllImages(term) },
networkCall = {
remoteDataSource.getImages(term) },
saveCallResult = {
val searchedImages = mutableListOf<Images>()
it.query.pages.values.filter {
it.thumbnail != null
}.map {
searchedImages.add(Images(it.pageid, it.thumbnail!!.source, term))
}
localDataSource.insertAll(searchedImages)
}
)
This is my viewmodel class
class ImagesViewModel @Inject constructor(
private val repository: WikiImageRepository
) : ViewModel() {
var images: LiveData<Resource<List<Images>>> = MutableLiveData()
fun fetchImages(search: String) {
images = repository.getImages(search)
}
}
From my fragment I am observing the variable
viewModel.images?.observe(viewLifecycleOwner, Observer {
when (it.status) {
Resource.Status.SUCCESS -> {
println(it)
}
Resource.Status.ERROR ->
Toast.makeText(requireContext(), it.message, Toast.LENGTH_SHORT).show()
Resource.Status.LOADING ->
println("loading")
}
})
I have to fetch new data on click of button viewModel.fetchImages(binding.searchEt.text.toString())
Function doesn't gets executed. Is there something I have missed out?
Upvotes: 2
Views: 498
Reputation: 11477
The liveData {}
extension function returns an instance of MediatorLiveData
liveData { .. emit(T) } // is a MediatorLiveData which needs a observer to execute
Why is the
MediatorLiveData
addSource block not executed ?
We need to always observe a MediatorLiveData
using a liveData observer else the source block is never executed
So to make the liveData block execute just observe the liveData,
performGetOperation(
databaseQuery = {
localDataSource.getAllImages(term) },
networkCall = {
remoteDataSource.getImages(term) },
saveCallResult = {
localDataSource.insertAll(it)
}
).observe(lifecyleOwner) { // observing the MediatorLiveData is necessary
}
In your case every time you call
images = repository.getImages(search)
a new instance of mediator liveData is created which does not have any observer. The old instance which is observed is ovewritten. You need to observe the new instance of getImages(...)
again on button click.
images.observe(lifecycleOwner) { // on button click we observe again.
// your observer code goes here
}
See MediatorLiveData and this
Upvotes: 1