Что такое LaunchedEffect и DisposableEffect в Jetpack Compose
Что проверяют
Понимаете ли вы, зачем нужны отдельные механизмы для побочных эффектов, и знаете ли роль ключей.
Как отвечать
Функция построения интерфейса должна быть чистой и может вызываться сколько угодно раз. Значит побочные эффекты нельзя писать прямо в её теле: они выполнялись бы при каждой перекомпозиции. Для них есть отдельные механизмы.
Первый запускает корутину при попадании в композицию и отменяет её при выходе. Нужен для загрузки данных, подписки на поток, показа уведомления, запуска анимации.
LaunchedEffect(jobId) {
viewModel.load(jobId)
}Ключи это главное в его поведении: при их изменении текущая корутина отменяется и запускается новая. Отсюда два типовых сценария: постоянный ключ означает выполнение один раз за время жизни, а меняющийся означает перезапуск при смене данных. Ошибка с ключами даёт либо повторные загрузки при каждом обновлении, либо застывшие данные при переходе на другой элемент.
Второй предназначен для эффектов с обязательной очисткой, не связанных с корутинами: регистрация слушателя, наблюдателя жизненного цикла, обратного вызова системы. Блок очистки обязателен, и в этом смысл конструкции.
DisposableEffect(lifecycleOwner) {
val observer = LifecycleEventObserver { _, event -> ... }
lifecycleOwner.lifecycle.addObserver(observer)
onDispose { lifecycleOwner.lifecycle.removeObserver(observer) }
}Рядом стоят ещё три механизма, которые полезно назвать:
- эффект после успешной композиции для синхронизации с кодом вне Compose;
- область корутин, привязанная к композиции, для запуска работы из обработчика нажатия, а не при появлении на экране;
- обёртка над изменяющимся значением, позволяющая долгоживущему эффекту видеть свежее значение без перезапуска. Тонкая, но очень полезная вещь.
Где спотыкаются
Пишут запросы прямо в теле функции интерфейса.
Ставят постоянный ключ там, где нужен перезапуск при смене данных.
Забывают блок очистки и получают утечку подписки.
Запускают корутину из обработчика нажатия через эффект появления.