我试图在MVVM中同时使用LiveData和协程,但我可能缺少一些简单的东西。
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
。
我假设是这种情况,因为我正在使用协程viewModelScope.launch
。
override suspend fun getWeather(): LiveData<Weather> {
return withContext(IO){
initWeatherData()
return@withContext weatherDao.getWeather()
}
}
我该如何解决?
答案 0 :(得分:0)
如下更改签名:
var weather = MutableLiveData<Weather>();
此外,您应该只返回Weather
对象,而不返回LiveData <>
因此您应该更改getWeather()
的签名以返回: Weather
。
答案 1 :(得分:0)
您可以将weather
属性声明为lateinit
:
private lateinit var weather: LiveData<String>
或将其设为 nullable :
private var weather: LiveData<String>? = null
如果您确定在首次使用该属性之前会对其进行初始化,请使用lateinit
,否则使其为空。
答案 2 :(得分:0)
在Kotlin中,默认情况下,每个属性都必须初始化(即使具有null的可空类型)。
您可以直接在声明中或init块中初始化属性。
您的代码存在的问题是,启动函数可以在init块完成后继续运行,并且编译器知道这一点。所以,它告诉您-不要指望它。
如前所述,您可以使用 lateinit 来声明稍后将初始化属性,如果您确定该属性会在使用前发生。
答案 3 :(得分:-1)
weather
必须使用该类的实例进行初始化,因为您没有说过它可以为null,并且您没有使用lateinit
关键字(在这种情况下不应该使用)。 / p>
launch
是一个异步协程调用,该调用会立即返回,但将来会在某个时候执行。这意味着您的init
块可以完成并返回而无需初始化weather
。
改为使用runBlocking
。这将阻塞,直到您将结果放在init
块中为止,因此请确保实例化时天气不为null。像这样:
init {
weather = runBlocking {
weatherRepository.getWeather()
}
}
您也可以将任何协程上下文分配器传递给runBlocking
。
或者-坚持使用协程,但是像下面这样加入init块:
init {
val job = viewModelScope.launch {
weather = weatherRepository.getWeather()
}
job.join()
}