SNM
SNM

Reputation: 6795

How to retry a request inside my viewmodel

I'm trying to retry the logic of getting data from Firebase, what my app does is the follow.

If there is no internet connection it will trigger the Failure Resource and will show a retry button, but when I click this button, it seems that the viewmodel does not request again the data, instead is just showin my progress without requesting again the data to my repo

UI

 viewModel.getPrizes.observe(viewLifecycleOwner, Observer { it ->
            when(it){
                is Resource.Loading -> {
                  // Loading...
                }
                is Resource.Success -> {
                    hideProgress()
                    setArrayData(it.data)
                }
                is Resource.Failure -> {
                    hideProgress()
                    hidePrizes()
                    retry_constrain.visibility = View.VISIBLE
                    btn_retry.setOnClickListener{
                        viewModel.getPrizes
                        showProgress()
                        retry_constrain.visibility = View.GONE
                    }
                    Toast.makeText(
                        requireContext(),
                        "An error has ocourred:${it.throwable.message}",
                        Toast.LENGTH_SHORT
                    ).show()
                }
            }
        })

What I spect here is in my Resource.Failure to request again the data after pressing my btn_retry but instead, it only shows my progress bar and nothing happens

ViewModel

class PrizesViewModel(private val useCase:IPrizes): ViewModel() {

    val getPrizes = liveData(Dispatchers.IO) {
        emit(Resource.Loading())
        try{
            val prizes = useCase.fetchPrizes()
            emit(prizes)
        }catch (e:Exception){
            Crashlytics.logException(e.cause)
            emit(Resource.Failure(e.cause!!))
        }
    }
}

Why is not re-fetching my values after calling again viewModel.getPrizes in my Resource.Failure ?

Upvotes: 0

Views: 1203

Answers (2)

SNM
SNM

Reputation: 6795

What I ended up doing was a Transformation, since a Transformation can be triggered whenever the mutable value changes, I can retry the whole coroutine doing so

 private val shouldRetry = MutableLiveData<Boolean>()
    val fetchPrizes: LiveData<Resource<Prizes>> = Transformations.switchMap(shouldRetry) {
        liveData(context = viewModelScope.coroutineContext + Dispatchers.IO) {
          emit(Resource.Loading())
        try{
            val prizes = useCase.fetchPrizes()
            emit(prizes)
        }catch (e:Exception){
            Crashlytics.logException(e.cause)
            emit(Resource.Failure(e.cause!!))
        }
        }
    }

    fun retryData(retry: Boolean) {
        shouldRetry.value = retry
    }

Then from my UI I just call viewModel.retryData(true) whenever I want

Upvotes: 0

Emmanuel
Emmanuel

Reputation: 13223

The LiveData from the second call to viewModel.getPrizes has no Observers attached to it, and hence it will not get a value until there is one.

You would have to call viewModel.getPrizes.observe(...) again inside the current Observer which is not optimal.

You will have to rethink your design a bit so you can trigger a new call to useCase.fetchPrizes() and still get the new value by observing the original LiveData.

Upvotes: 2

Related Questions