我正在尝试在正在构建的天气应用中实现SwipeToRefreshLayout。当用户滑动刷新时,应更新ViewModel中的数据,然后相应地更新视图。
这是我的CurrentWeatherFragment的摘要:
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProviders.of(this, viewModelFactory)
.get(WeatherResponseViewModel::class.java)
pullToRefresh.setOnRefreshListener(this)
bindUI()
}
override fun onRefresh() {
viewModel = ViewModelProviders.of(this, viewModelFactory)
.get(WeatherResponseViewModel::class.java)
bindUI()
pullToRefresh.isRefreshing = false
}
private fun bindUI() = launch {
val currentWeather = viewModel.weather.await()
currentWeather.observe(this@CurrentWeatherFragment, Observer {
if (it == null) return@Observer
loading_icon.visibility = View.GONE
updateLocation("Raleigh")
updateDateToToday()
updateTemperatures(it.currently.temperature.roundToInt(),
it.currently.apparentTemperature.roundToInt(),
it.daily.data[0].temperatureMin.roundToInt(),
it.daily.data[0].temperatureMax.roundToInt())
updateDescription(it.currently.summary)
updateEnvironmentals((it.currently.humidity * 100).roundToInt(), it.currently.windSpeed.roundToInt())
updateWeatherIcon(it.currently.icon)
updateTempChart(it)
updatePrecipChart(it)
})
}
我的ViewModel:
class WeatherResponseViewModel (
private val forecastRepository: ForecastRepository,
unitProvider: UnitProvider
) : ViewModel() {
private val unitSystem = unitProvider.getUnitSystem()
val isMetric: Boolean
get() = unitSystem == UnitSystem.METRIC
val weather by lazyDeferred {
forecastRepository.getWeather()
}
}
和我的lazyDeferred实现:
fun <T> lazyDeferred(block: suspend CoroutineScope.() -> T): Lazy<Deferred<T>> {
return lazy {
GlobalScope.async {
block.invoke(this)
}
}
}
当前,使用此设置,在应用程序启动时或在切换至片段时加载片段时,会调用ViewModel中的ForecastRepository.getWeather()函数,但在滑动刷新时不会调用该片段。如何在ViewModel中获取天气变量进行更新,以便视图可以观察到变化?
答案 0 :(得分:3)
首先,您的代码中有一些关于Coroutine和ViewModel的错误实现。
请勿在{{1}}中再次实例化ViewModel。
相反,只要在以下情况下在视图模型中创建并调用refresh方法 SwipeRefreshLayout被拉。
如果可以,请不要在应用程序中使用GlobalScope。
它可能导致工作泄漏,并且不遵循结构化并发规则。
请使用onRefresh
块。
请勿使用coroutineScope{}
中的LifecycleOwner
来观察片段Fragment
。它可以为LiveData
生成重复的观察者。
相反,请使用LiveData
个片段实例。
这是因为,当将片段恢复到堆栈中时,会重新创建片段的视图,但会重新创建片段。
如果您将观察者生命周期与片段视图匹配,则viewLifecycleOwner
不会在视图被破坏后保留。
刷新方式
不要使用惰性块。好像Ovserver
的答案一样没用。
答案 1 :(得分:1)
来自Kotlin委派的属性:
惰性属性:仅在首次访问时才计算该值;
请勿将lazy
用于可变数据