Search code examples
androidkotlinandroid-livedatakotlin-coroutinesmutablelivedata

Using liveData{} coroutine builder on Dispatchers.IO thread


My code

fun weatherByCity(cityName: String): LiveData<Resource<Response>> = liveData(Dispatchers.IO) {
    val response = appRepository.weatherByCity(cityName)
    emit(response)
}

fun weatherByZipCode(zipCode: String): LiveData<Resource<Response>> = liveData(Dispatchers.IO) {
    val response = appRepository.weatherByZipCode(zipCode)
    emit(response)
}

fun weatherByLocation(latLong: String): LiveData<Resource<Response>> = liveData(Dispatchers.IO) {
    val response = appRepository.weatherByLocation(lat?:"", long?:"")
    emit(response)
}

Here I am using three liveData{} blocks they get data from repository and retrofit. But they have same return type LiveData<Resource<Response>>. Can I use single liveData{} for all three, if yes then how to do that? One more question, using liveData(Dispatchers.IO) or using liveData{} (without Dispatchers.IO) will make any difference?


Solution

  • Using liveData(Dispatchers.IO) or using liveData{} (without Dispatchers.IO) will make any difference?

    Yes, by default the liveData{} builder will be called on the UI(Main) thread, but since you have explicitly added liveData(Dispatchers.IO){} it will now be scheduled on IO thread.

    What I do personally is, let liveData{} run on UI thread as usual but call all my suspend functions on IO thread, just to make sure that the emit() operation executes on UI thread without any delay. for ex:

    val someData = liveData{
    
     val dataFromNetwork = getDataFromNetwork()
     emit(dataFromNetwork)
    
    }
    
    
    
    suspend fun getDataFromNetwork() = withContext(Dispatchers.IO){
    
                                 apiClient.getData()
         }
    

    Can I use single liveData{} for all three, if yes then how to do that?

    Well, it's hard to tell this because it is a matter of design choice and will vary from subject to subject and also depend on how you are consuming the results from all the three functions(whether all three methods are called sequentially or parallely ). Still, I'll try to give a direction,

    So let's say, you come up with something like this,

    fun getWeatherData(criteriaToGetWeatherData:String) = liveData(Dispatchers.IO){
    
        when(criteriaToGetWeatherData){
    
          isByCity -> {
                         val response = appRepository.weatherByCity(cityName)
                         emit(response)
                      }
    
          isByZipCode -> {
                            val response = appRepository.weatherByZipCode(zipCode)
                            emit(response)
                         }
    
    
          isByLocation -> {
                            val response = appRepository.weatherByLocation(lat?:"", long?:"")
                            emit(response)
    
                       }
    
          }
    
    }
    

    You have now reduced the boilerplate code of three functions to a single function.

    But consider the following things,

    1. Now your single function is doing the job of three functions.
    2. Your function is already large with the future scope of further extension.
    3. You have disobeyed Open/Close principle, your function will be modified whenever a new weather criterion comes in the future.
    4. The worst, all the repository methods are asynchronous functions, assuming a case where all three are called in quick succession there is no guarantee and no way to differentiate which one returned first and which emit() has which weather data. Further, if you only have a single subscriber observing getWeatherData() you won't have any idea for which of three inner methods you were notified.

    According to Clean Code by Uncle Bob Martin:

    Functions should do one thing. They should do it well, They should do it only.

    At the end of the day, we have to remember that code readability is the ultimate king. So following the KISS( keep it simple stupid) principle, I would have left the three functions as it is.