Как обрабатывать события, если экран находится в неподходящем состоянии
Что проверяют
Различаете ли вы состояние экрана и одноразовые события вроде навигации или снэкбара, и знаете ли, что с событием происходит, когда экран в фоне, пересоздаётся или показывает загрузку. Следом обычно спрашивают, почему SharedFlow теряет события.
Как отвечать
Разведите две проблемы. Первая: жизненный цикл. UI подписывается только в активном состоянии, через repeatOnLifecycle(Lifecycle.State.STARTED) во фрагменте или collectAsStateWithLifecycle() в Compose. В фоне подписка останавливается, при возврате возобновляется. Данные переживают поворот в ViewModel, смерть процесса в SavedStateHandle.
Вторая: доставка событий. Варианты с ценой:
- событие как часть состояния: так советует гайд Android по архитектуре. В
UiStateлежит, например,userMessage, экран показывает его и вызываетonMessageShown(), ViewModel очищает поле. Ничего не теряется, поворот не повторяет показ; ChannelплюсreceiveAsFlow(): событие ждёт в буфере, пока экран не подпишется. Годится для навигации, но в редком случае событие теряется, если подписку отменили между получением и обработкой;SharedFlowсreplay = 0: событие без подписчика пропадает, для одноразовых действий это опасно.
И бизнес-смысл «неподходящего состояния». Если экран в Loading, а пользователь снова жмёт «Оплатить», решает ViewModel: у каждого состояния свой набор допустимых действий, лишние игнорируются или ставятся в очередь. В MVI это редьюсер (state, intent) -> state, его легко покрыть тестами. Заблокированная кнопка в UI полезна, но защитой не считается.
Где спотыкаются
Собирают поток в lifecycleScope.launch без привязки к жизненному циклу. Экран обновляется в фоне, а транзакция фрагмента после onSaveInstanceState падает с IllegalStateException. Лечить это через commitAllowingStateLoss() значит прятать ошибку.
Возрождают SingleLiveEvent или берут launchWhenStarted. Первый уведомляет только одного подписчика, второй библиотека Lifecycle объявила устаревшим.
Отвечают про BroadcastReceiver и Service. К событиям экрана они не относятся, а фоновые сервисы с Android 8 серьёзно ограничены.