WISHY
WISHY

Reputation: 11999

Using livedata coroutine doesn't gets executed

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

Answers (1)

Santanu Sur
Santanu Sur

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

Related Questions