Search code examples
androidkotlinmvvmviewmodelkotlin-coroutines

Is this a proper usage of Coroutines IO dispatcher in ViewModel?


I want to make sure if the following is a proper use of the IO dispatcher:

  • In a ViewModel, I call methods from the repository which calls methods from an api (Retrofit is used as the networking library). I read that for any network methods I can use the IO dispatcher but by reading many examples I didn't find any example calling the IO dispatcher.

Would it be proper if I made use of it?

This is the code without the dispatchers

private suspend fun getNews() = viewModelScope.launch {
   _newsResponse.postValue(Resource.loading(null))
   try {
     repository.getNews().let {
       if (it.isSuccessful){
          _newsResponse.postValue(Resource.success(it.body()))
       }else{
          _newsResponse.postValue(Resource.error(it.errorBody().toString(), null))
       }
    }
}

And this is the code using IO Dispatcher

private suspend fun getNews() = viewModelScope.launch {
   withContext(Dispatcher.IO){

     _newsResponse.postValue(Resource.loading(null))
       try {
           repository.getNews().let {
           if (it.isSuccessful){
              _newsResponse.postValue(Resource.success(it.body()))
           }else{
              _newsResponse.postValue(Resource.error(it.errorBody().toString(), null))
          }
        }
    }
}
  1. What would be the proper way to do (with or without the IO dispatcher?
  2. Is withContext(Dispatcher.IO) same as when I do viewmodelscope.launch(IO)?

Solution

  • If repository.getNews() is a properly composed suspend function, you don’t need to specify a dispatcher at all. A properly composed suspend function doesn’t block, it suspends, so it is safe to call from any context without specifying dispatcher. An improperly composed suspend function would be one that internally calls a blocking function without internally specifying a dispatcher that can handle its type of blocking calls.

    Retrofit provides suspend functions for making requests so you should be able to easily compose repository.getNews() in a proper way.

    You also don’t need to be using liveData.postValue() since the view model scope is on the main dispatcher by default. You can use the standard value setter property.

    Regarding your second question, these two ways of doing it would be equivalent in this specific case since you wrap the entire contents of your coroutine in the withContext block. But like I said, you don’t need to specify dispatcher at all so you should use a bare launch call.