【问题标题】:Good solution for call one method from ViewModel multiple times多次从 ViewModel 调用一种方法的好解决方案
【发布时间】:2021-10-24 18:09:26
【问题描述】:

我需要从 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 可以从循环中的 4 次迭代中返回数组中的 80 项。

你知道我能做些什么吗? 感谢帮助

【问题讨论】:

  • 你能展示你的getCurrentWeatherByCity函数吗?
  • @Tenfour04 更新了问题。你可以在那里看到:)

标签: android kotlin mvvm


【解决方案1】:

使用挂起函数可以更轻松地解决这个问题,我就是这样做的。

首先让你的 repo 使用一个直接返回 WeatherModel 而不是 LiveData&lt;WeatherModel&gt; 的挂起函数。它可以在失败时返回 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)
}

【讨论】:

  • 你知道我为什么在 repo 类的地图上得到Not enough information to infer type variable R 吗?我尝试修复它,但不知道为什么......
  • 我的意思是:map(Response&lt;WeatherModel&gt;::body)
  • 它只能访问 WeatherModel 中的字段
  • 哦,对了。我记错了await() 返回的内容。您可以删除整个地图线。
  • 是的,现在可以完美运行了。谢谢您的帮助! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-15
  • 1970-01-01
  • 1970-01-01
  • 2012-03-15
  • 1970-01-01
  • 2011-11-17
相关资源
最近更新 更多