Как работает StateFlow и чем он отличается от LiveData
Что проверяют
Понимаете ли вы, что StateFlow ничего не знает о жизненном цикле, и умеете ли безопасно собирать его в UI. Это главное практическое отличие, остальное детали.
Как отвечать
- StateFlow это горячий поток с одним всегда доступным значением: начальное обязательно,
valueчитается синхронно, новый подписчик сразу получает текущее состояние. - StateFlow конфлейтит значения и сравнивает их через
equals: одинаковое значение подряд подписчикам не придёт. Отсюда ловушка с мутабельным списком, который поменяли на месте и присвоили обратно: ссылка та же, эмиссии нет. Работайте с неизменяемыми копиями. - LiveData тоже хранит значение и не теряет его без наблюдателей, но подписка привязана к
LifecycleOwner: данные приходят только в активном состоянии, отписка автоматическая. Повторное присваивание того же значения LiveData наблюдателю отдаст, аsetValueтребует главного потока, из фонового нуженpostValue. - У StateFlow такой защиты нет, поэтому в UI собирают так:
viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.state.collect { render(it) }
}
}В Compose то же самое делает collectAsStateWithLifecycle().
- Для разовых событий (навигация, снекбар) StateFlow не подходит: состояние переиграется после поворота экрана. Нужен
SharedFlowбез реплея илиChannelсreceiveAsFlow(). - Выбор сегодня: Flow и StateFlow как основной инструмент, особенно в Compose. LiveData остаётся в старом коде и в связке с Data Binding.
Где спотыкаются
Пишут lifecycleScope.launch { state.collect { } } без repeatOnLifecycle. Сбор продолжается на невидимом экране, приложение работает вхолостую, а обновление UI оттуда приводит к падениям.
Утверждают, что LiveData без подписчиков теряет значение. Значение хранится, отличие в доставке.
Ждут эмиссию после изменения элемента внутри списка, забыв про сравнение по equals.
Ставят collect до изменения состояния в линейном коде и удивляются, что дальше ничего не идёт: у горячего потока collect не завершается никогда.