我试图在MVVM中一起使用LiveData和Coroutines,我可能会遗漏一些简单的东西。
class WeatherViewModel (
private val weatherRepository: ForecastRepository
) : ViewModel() {
var weather: LiveData<Weather>;
/**
* Cancel all coroutines when the ViewModel is cleared.
*/
@ExperimentalCoroutinesApi
override fun onCleared() {
super.onCleared()
viewModelScope.cancel()
}
init {
viewModelScope.launch {
weather = weatherRepository.getWeather()
}
}
}
但我正在让Property must be initialized or be abstract
在weather
函数中分配init
。我假设这是因为我使用coroutines viewModelScope.launch
。
override suspend fun getWeather(): LiveData<Weather> {
return withContext(IO){
initWeatherData()
return@withContext weatherDao.getWeather()
}
}
我该如何解决?
更改签名如下:
var weather = MutableLiveData<Weather>();
另外,你应该只返回一个Weather
对象而不是LiveData <>所以你应该改变getWeather()
的签名来返回: Weather
。
必须使用类的实例化来初始化weather
,因为您没有说它可以为null,并且您没有使用lateinit
关键字(在这种情况下您不应该使用它)。
launch
是一个异步协程调用,它会立即返回,但将来会在某个时刻执行。这意味着你的init
块完成并返回而没有初始化weather
。
请改用runBlocking
。这将阻塞,直到您在init
块中得到结果,因此保证实例化时天气不为空。就像是:
init {
weather = runBlocking {
weatherRepository.getWeather()
}
}
您也可以将哪个coroutine上下文调度程序传递给runBlocking
。
或者 - 坚持协程,但加入init块,如:
init {
val job = viewModelScope.launch {
weather = weatherRepository.getWeather()
}
job.join()
}