多次从 ViewModel 调用一个方法的好解决方案
Good solution for call one method from ViewModel multiple times
我需要从 MVVM 多次调用一种方法,以便 API 调用并将结果发送到回收器视图。我不知道用户需要执行多少次,因为这取决于列表大小。例如:
list: ["FirstElement", "SecondElement", "..", "..."]
在代码中,我尝试在循环中调用这样的方法:
for (city in list) {
viewModel.getCurrentWeatherByCity(city, appID, unit).observe(viewLifecycleOwner, {
result.add(it) // here is arraylist for recyclerview
})
}
val adapterRecycler = LocationListWeatherRecyclerAdapter(result) // init adapter for recycler
setUpRecyclerData(adapterRecycler) // method for setup recyclerview
查看模型方法:
fun getCurrentWeatherByCity(city: String, appID: String, units: String): LiveData<WeatherModel> {
return repository.getCurrentWeatherByCity(city, appID, units)
}
和存储库方法:
fun getCurrentWeatherByCity(city: String, appID: String, units: String ) : LiveData<WeatherModel> {
apiService.getCurrentWeatherByCity(city, appID, units).enqueue(object : Callback<WeatherModel>{
override fun onResponse(call: Call<WeatherModel>, response: Response<WeatherModel>) {
if (response.isSuccessful) {
weatherData.postValue(response.body())
} else {
}
}
override fun onFailure(call: Call<WeatherModel>, t: Throwable) {
}
})
return weatherData
}
但我知道这是错误的解决方案,因为结果是在后台执行的,而且是错误的。这 for 可以 return 80 个数组中的项目来自循环中的 4 次迭代。
你知道我可以做什么吗?
感谢帮助
使用挂起函数可以更轻松地解决这个问题,我就是这样做的。
首先让你的 repo 使用 return WeatherModel
直接而不是 LiveData<WeatherModel>
的挂起函数。它可以 return 失败时为 null,或者如果你愿意,你可以做一些更复杂的事情。
suspend fun getCurrentWeatherByCity(city: String, appID: String, units: String ) : WeatherModel? {
return runCatching { apiService.getCurrentWeatherByCity(city, appID, units).await() }
.getOrNull()
}
然后您可以在 ViewModel 中创建一个函数,它接受城市列表并并行运行 api 调用,如下所示:
fun getCurrentWeatherByCities(cities: List<String>, appID: String, units: String) = liveData<List<WeatherModel>> {
val weatherModels = cities.map { city ->
async { repository.getCurrentWeatherByCity(city, appID, units) }
}
.awaitAll()
.filterNotNull()
emit(weatherModels)
}
然后在你的片段中,观察它并在观察者中设置适配器列表。
viewModel.getCurrentWeatherByCities(cities, appID, unit).observe(viewLifecycleOwner, {
val adapterRecycler = LocationListWeatherRecyclerAdapter(it)
setUpRecyclerData(adapterRecycler)
}
我需要从 MVVM 多次调用一种方法,以便 API 调用并将结果发送到回收器视图。我不知道用户需要执行多少次,因为这取决于列表大小。例如:
list: ["FirstElement", "SecondElement", "..", "..."]
在代码中,我尝试在循环中调用这样的方法:
for (city in list) {
viewModel.getCurrentWeatherByCity(city, appID, unit).observe(viewLifecycleOwner, {
result.add(it) // here is arraylist for recyclerview
})
}
val adapterRecycler = LocationListWeatherRecyclerAdapter(result) // init adapter for recycler
setUpRecyclerData(adapterRecycler) // method for setup recyclerview
查看模型方法:
fun getCurrentWeatherByCity(city: String, appID: String, units: String): LiveData<WeatherModel> {
return repository.getCurrentWeatherByCity(city, appID, units)
}
和存储库方法:
fun getCurrentWeatherByCity(city: String, appID: String, units: String ) : LiveData<WeatherModel> {
apiService.getCurrentWeatherByCity(city, appID, units).enqueue(object : Callback<WeatherModel>{
override fun onResponse(call: Call<WeatherModel>, response: Response<WeatherModel>) {
if (response.isSuccessful) {
weatherData.postValue(response.body())
} else {
}
}
override fun onFailure(call: Call<WeatherModel>, t: Throwable) {
}
})
return weatherData
}
但我知道这是错误的解决方案,因为结果是在后台执行的,而且是错误的。这 for 可以 return 80 个数组中的项目来自循环中的 4 次迭代。
你知道我可以做什么吗? 感谢帮助
使用挂起函数可以更轻松地解决这个问题,我就是这样做的。
首先让你的 repo 使用 return WeatherModel
直接而不是 LiveData<WeatherModel>
的挂起函数。它可以 return 失败时为 null,或者如果你愿意,你可以做一些更复杂的事情。
suspend fun getCurrentWeatherByCity(city: String, appID: String, units: String ) : WeatherModel? {
return runCatching { apiService.getCurrentWeatherByCity(city, appID, units).await() }
.getOrNull()
}
然后您可以在 ViewModel 中创建一个函数,它接受城市列表并并行运行 api 调用,如下所示:
fun getCurrentWeatherByCities(cities: List<String>, appID: String, units: String) = liveData<List<WeatherModel>> {
val weatherModels = cities.map { city ->
async { repository.getCurrentWeatherByCity(city, appID, units) }
}
.awaitAll()
.filterNotNull()
emit(weatherModels)
}
然后在你的片段中,观察它并在观察者中设置适配器列表。
viewModel.getCurrentWeatherByCities(cities, appID, unit).observe(viewLifecycleOwner, {
val adapterRecycler = LocationListWeatherRecyclerAdapter(it)
setUpRecyclerData(adapterRecycler)
}