SNM
SNM

Reputation: 6795

ViewModel prevent refetching of data

My viewModel refetches my data causing my shimmer to keep executing each time I get to this fragment, and also the data is beign refetched which is making my bill goes up on Firebase

How can I prevent to refetch again the data each time my fragment pops up ?

From my view

 viewModel.fetchShops(location).observe(viewLifecycleOwner, Observer {
            when(it){
                is Resource.Loading -> {
                    shimmer.visibility = View.VISIBLE
                    shimmer.startShimmer()}
                is Resource.Success -> {
                    shimmer.visibility = View.GONE
                    shimmer.stopShimmer()
                    adapter.setItems(it.data)
                }
                is Resource.Failure -> {
                    Toast.makeText(requireContext(),"Error fetching data",Toast.LENGTH_SHORT).show()
                }
            }
        })

I call this in my onViewCreated() so each time this fragment recreates my Resource.Loading fires as well as the fetchShops(location) and this fetches again to my database, I want it to fetch just once each time I come back to this fragment, any idea?

ViewModel

   fun fetchShops(location:String) = liveData(Dispatchers.IO) {
            emit(Resource.Loading())
            try{
                emit(repo.fetchShops(location))
            }catch (e:Exception){
                emit(Resource.Failure(e))
            }
        }

Upvotes: 0

Views: 291

Answers (1)

ianhanniballake
ianhanniballake

Reputation: 199900

You're creating a new LiveData instance every time fetchShops() is called. This means that any previously created LiveData (and the previous value it stores) is lost.

Instead, you should Transform your LiveData by using your location as the input into creating your liveData { } block as per the liveData with Transformations .

private val locationQuery = MutableLiveData<String>

// Use distinctUntilChanged() to only requery when the location changes
val shops = locationQuery.distinctUntilChanged().switchMap { location ->
    // Note we use viewModelScope.coroutineContext to properly support cancellation
    liveData(viewModelScope.coroutineContext + Dispatchers.IO) {
        emit(Resource.Loading())
        try{
            emit(repo.fetchShops(location))
        }catch (e:Exception){
            emit(Resource.Failure(e))
        }
    }
}

fun setLocation(location: String) {
    locationQuery.value = location
}

You can then use this by updating your Fragment:

// Set the current location
viewModel.setLocation(location)

// Observe the shops
viewModel.shops.observe(viewLifecycleOwner, Observer {
        when(it){
            is Resource.Loading -> {
                shimmer.visibility = View.VISIBLE
                shimmer.startShimmer()}
            is Resource.Success -> {
                shimmer.visibility = View.GONE
                shimmer.stopShimmer()
                adapter.setItems(it.data)
            }
            is Resource.Failure -> {
                Toast.makeText(requireContext(),"Error fetching data",Toast.LENGTH_SHORT).show()
            }
        }
    })

Upvotes: 2

Related Questions