2

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?

3
  • I'm trying to move this file to the data layer but it's impossible, because it's pure java, and LiveData can't be imported. Any solution? Commented Aug 2, 2022 at 9:20
  • @Patrick which file? Why can't live data be imported? Commented Aug 5, 2022 at 5:23
  • performGetOperation function. I have a module Data, which is a java-library, and I cannot not import this function to this layer for the operations Commented Aug 7, 2022 at 7:48

1 Answer 1

1

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

Sign up to request clarification or add additional context in comments.

4 Comments

I am observing it in my fragment and I have to fetch new data on button click. Still the function doesn't gets executed, I have updated the question. Can you please take a look.
but u are never observing perforGetOperation(...) which needs an observer. We need to observe perforGetOperation(...) atleast with a blank observer to make it execute as i have shown in the answer @WISHY
I am observing that from getImages fun
on button click u need to observe again , its a separate instance now @WISHY it creates a new instance every time

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.