LiveData и сопрограммы - свойство должно быть инициализировано или абстрактно - PullRequest
1 голос
/ 16 апреля 2019

Я пытаюсь использовать LiveData и сопрограммы вместе в MVVM, и мне может не хватать чего-то простого.

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()
    }
}

Как мне это исправить?

Ответы [ 3 ]

0 голосов
/ 17 апреля 2019

weather должен быть инициализирован с созданием экземпляра класса, потому что вы не сказали, что он может быть нулевым, и вы не используете ключевое слово lateinit (что в данном случае не следует).

launch - это асинхронный вызов сопрограммы, который немедленно возвращается, но будет выполнен в какой-то момент в будущем. Это означает, что ваш блок init завершается и возвращается без инициализации weather.

Вместо этого используйте runBlocking. Это будет блокировать до тех пор, пока вы не получите результат в блоке init, и, таким образом, гарантируете, что погода не будет нулевой при создании экземпляра. Что-то вроде:

init {
    weather = runBlocking {
        weatherRepository.getWeather()
    }
}

Вы также можете передать любой когда-либо диспетчер контекста сопрограмм в runBlocking.

Или - придерживайтесь сопрограммы, но присоединяйтесь к блоку инициализации, как:

init {
    val job = viewModelScope.launch {
        weather = weatherRepository.getWeather()
    }
    job.join()
} 
0 голосов
/ 19 апреля 2019

Вы можете объявить weather свойство как lateinit:

private lateinit var weather: LiveData<String>

Или сделать его обнуляемым :

private var weather: LiveData<String>? = null

Если вы уверены, что свойство будет инициализировано перед его первым использованием, используйте lateinit, иначе сделайте его обнуляемым .

0 голосов
/ 16 апреля 2019

Измените подпись следующим образом:

var weather =  MutableLiveData<Weather>();

Кроме того, вы должны вернуть только Weather объект, а не LiveData <> поэтому вы должны изменить подпись getWeather(), чтобы вернуть : Weather.

...