Как подписываться на изменения значений в Jetpack Compose
Что проверяют
Понимаете ли вы, что в Compose не подписываются вручную: чтение State во время композиции само регистрирует зависимость. Проверяют, знаете ли вы, как подключить потоки из ViewModel и где запускать побочные эффекты. Следом обычно спрашивают про derivedStateOf или про разницу collectAsState и collectAsStateWithLifecycle.
Как отвечать
Механизм: снапшот-система Compose отслеживает, какие State прочитаны в каждой области рекомпозиции, и при изменении значения перезапускает только эти области.
Инструменты по задачам:
- локальное состояние:
var count by remember { mutableStateOf(0) }, для примитивовmutableIntStateOfбез упаковки.rememberSaveableпереживает поворот экрана и смерть процесса; - из ViewModel:
StateFlowсобирается черезcollectAsStateWithLifecycle()изlifecycle-runtime-compose, он перестаёт собирать поток, когда экран ушёл в фон. ДляLiveDataестьobserveAsState(); - производное состояние:
derivedStateOf, когда результат меняется реже исходника, например кнопка «наверх» приfirstVisibleItemIndex > 0; - реакция на изменение:
LaunchedEffect(key)перезапускает корутину при смене ключа, аsnapshotFlow { state.value }превращает State в Flow, чтобы применитьdebounceилиdistinctUntilChanged; - свежее значение в долгом эффекте:
rememberUpdatedState, чтобы эффект не перезапускался, а внутри видел актуальный колбэк.
Хорошо показать общий поток данных: состояние течёт вниз параметрами, события поднимаются лямбдами (state hoisting), а экран подписан на один UiState.
Где спотыкаются
Используют collectAsState() на экране с дорогим потоком. Сбор продолжается в фоне, пока композиция жива, а версия с lifecycle его останавливает.
Пишут mutableStateOf без remember. Каждая рекомпозиция создаёт новое состояние, и значение сбрасывается.
Делают побочный эффект прямо в теле composable, например отправку аналитики. Он выполнится на каждую рекомпозицию, а место ему в LaunchedEffect.