Вопрос:

Как обновить данные ViewModel, используя сопрограмму ленивой загрузки Kotlin?

android kotlin coroutine kotlin-coroutines

15 просмотра

2 ответа

96 Репутация автора

Я пытаюсь реализовать 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)
        }
    }
}

В настоящее время при такой настройке функция прогнозReRepository.getWeather () в ViewModel вызывается, когда фрагмент загружается либо при запуске приложения, либо при переключении на него, но при обновлении смахивания он не вызывается. Как я могу получить переменную погоды в ViewModel для обновления, чтобы представление могло наблюдать изменение?

Автор: cpgreen2 Источник Размещён: 11.08.2019 02:49

Ответы (2)


0 плюса

117 Репутация автора

Во-первых, в вашем коде есть несколько неправильных реализаций Coroutine и ViewModel.

  1. Не повторяйте экземпляр ViewModel снова в onRefresh.

    Вместо этого просто создайте и вызовите метод refresh в вашей модели представления при извлечении SwipeRefreshLayout.

  2. Не используйте GlobalScope в своем приложении, если можете.

    Это может вызвать утечку работы и не следует правилу структурированного параллелизма.

    Вместо этого используйте coroutineScope{}блок.

  3. Не следует использовать LifecycleOwnerв Fragmentтечение наблюдения LiveDataв фрагменте. Он может генерировать дубликат наблюдателя для LiveData.

    Вместо этого используйте viewLifecycleOwnerэкземпляр фрагмента.

    Это происходит потому, что при восстановлении фрагмента в заднем стеке представления фрагмента воссоздаются, но фрагмент.

    Если вы сопоставите свой жизненный цикл наблюдателя с представлениями во фрагменте, Ovservers не останется после уничтожения представления.


Способ обновить

Не используйте ленивый блок. Кажется бесполезным, как @Stanislav Bondarответ.

Автор: MJ Studio Размещён: 11.08.2019 08:16

0 плюса

3737 Репутация автора

От Kotlin делегированных свойств:

ленивые свойства: значение вычисляется только при первом доступе;

Не используйте lazyдля изменяемых данных

Автор: Stanislav Bondar Размещён: 11.08.2019 10:37
Вопросы из категории :
32x32