Ali
Ali

Reputation: 9994

Multiple state for StateFlow in MVVM

I have following method in Repository which I call in ViewModel init method :

suspend fun fetchShows() {
    _shows.value = Resource.loading()
    dao.getShows().let { showsFromDb ->
        flow {
            if (showsFromDb.isEmpty()) {
                if (context.isNetworkAvailable()) {
                    val apiShows = getRefreshedShows()
                    emit(Resource.success(apiShows))
                } else {
                    emit(Resource.error(context.getString(R.string.failed_network_msg)))
                }
            } else {
                emit(Resource.success(showsFromDb.asDomainModel()))
                try {
                    val apiShows = getRefreshedShows()
                    emit(Resource.update(apiShows))
                } catch (err: Exception) {
                    Timber.e(err)
                }
            }
        }
    }.flowOn(contextProvider.io)
        .catch {
            _shows.value = Resource.error(context.getString(R.string.failed_loading_msg))
        }.collect {
            _shows.value = it
        }
}

here is my ViewModel :

class MainViewModel(
    private val repository: ShowRepository
) : ViewModel() {

    private val _shows = repository.shows
    val shows: StateFlow<Resource<List<Show>>>
        get() = _shows

    init {
        refreshShows()
    }

    fun refreshShows() {
        viewModelScope.launch {
            repository.fetchShows()
        }
    }
}

And I observe StateFlow in my Activity :

lifecycleScope.launch {
            viewModel.shows.collect { resource ->
                when (resource.status) {
                    Resource.Status.SUCCESS -> {
                        binding.loadingSpinner.hide()
                        binding.errorLayout.hide()
                        viewModelAdapter.submitList(resource.data)
                    }
                    Resource.Status.LOADING -> {
                        binding.loadingSpinner.show()
                        binding.errorLayout.hide()
                    }
                    Resource.Status.ERROR -> {
                        binding.loadingSpinner.hide()
                        binding.errorLayout.show()
                        binding.errorMsg.text = resource.message
                    }
                    Resource.Status.UPDATE -> {
                        viewModelAdapter.submitList(resource.data)
                    }
                    Resource.Status.IDLE -> {
                    }
                }
            }
        }

Is there any better solution to remove Update state and use Success state instead since they are doing the same thing?

Full source code can be found : https://github.com/AliRezaeiii/TVMaze-Cache

Upvotes: 1

Views: 752

Answers (1)

iamanbansal
iamanbansal

Reputation: 2752

If I understood correctly you want to do the same thing on success and update state.

lifecycleScope.launch {
        viewModel.shows.collect { resource ->
            when (resource.status) {
                Resource.Status.UPDATE,
                Resource.Status.SUCCESS -> {
                    binding.loadingSpinner.hide()
                    binding.errorLayout.hide()
                    viewModelAdapter.submitList(resource.data)
                }
                Resource.Status.LOADING -> {
                    binding.loadingSpinner.show()
                    binding.errorLayout.hide()
                }
                Resource.Status.ERROR -> {
                    binding.loadingSpinner.hide()
                    binding.errorLayout.show()
                    binding.errorMsg.text = resource.message
                }
               
                Resource.Status.IDLE -> {
                }
            }
        }
    }

OR you can simply avoid Resource.update(apiShows) by using Resource.success(apiShows) in your repository.

Upvotes: 1

Related Questions