在 Dispatchers.IO 线程上使用 liveData{} 协程构建器

Sha*_*rad 2 android kotlin android-livedata mutablelivedata kotlin-coroutines

我的代码

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)
}
Run Code Online (Sandbox Code Playgroud)

在这里,我使用了三个 liveData{} 块,它们从存储库中获取数据并进行改造。但它们具有相同的返回类型LiveData<Resource<Response>>。我可以对所有三个都使用单个 liveData{},如果是,那么该怎么做?还有一个问题,使用 liveData(Dispatchers.IO) 还是使用 liveData{}(不使用 Dispatchers.IO)会有什么不同?

iCa*_*ntC 7

使用 liveData(Dispatchers.IO) 或使用 liveData{}(不使用 Dispatchers.IO)会有什么不同?

是的,默认情况下,liveData{}构建器将在UI(Main)线程上调用,但由于您已明确添加liveData(Dispatchers.IO){}它,现在将在IO线程上调度它。

我个人所做的是,像往常一样liveData{}UI线程上运行,但suspendIO线程上调用我的所有函数,只是为了确保emit()操作在UI线程上执行没有任何延迟。例如:

val someData = liveData{

 val dataFromNetwork = getDataFromNetwork()
 emit(dataFromNetwork)

}



suspend fun getDataFromNetwork() = withContext(Dispatchers.IO){

                             apiClient.getData()
     }
Run Code Online (Sandbox Code Playgroud)

我可以对所有三个都使用单个 liveData{},如果是,那么该怎么做?

嗯,这很难说,因为这是设计选择的问题,会因主题而异,还取决于您如何使用所有三个函数的结果(所有三个方法是按顺序调用还是并行调用)。不过,我会尝试给出一个方向,

所以让我们说,你想出了这样的东西,

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)

                   }

      }

}
Run Code Online (Sandbox Code Playgroud)

您现在已将三个函数的样板代码缩减为一个函数。

但考虑以下几点,

  1. 现在,您的单个功能正在完成三个功能的工作。
  2. 您的功能已经很大,未来可以进一步扩展。
  3. 您违反了 Open/Close 原则,未来每当新的天气标准出现时,您的功能都会被修改。
  4. 最糟糕的是,所有repository方法都是异步函数,假设在快速连续调用所有三个方法的情况下,无法保证也无法区分哪个首先返回哪个emit()具有哪些天气数据。此外,如果您只有一个订阅者观察,getWeatherData()您将不知道您收到了三个内部方法中的哪一个。

根据鲍勃·马丁叔叔的清洁代码:

函数应该做一件事。他们应该做得很好,他们应该只做。

归根结底,我们必须记住,代码可读性是最终的王者。因此,遵循KISS(保持简单愚蠢)原则,我会保留这三个功能。