Жизненный цикл в Jetpack Compose Часть Android Jetpack.
Компоненты, учитывающие жизненный цикл, выполняют действия в ответ на изменение статуса жизненного цикла хост-объекта Activity. Артефакт androidx.lifecycle.compose предоставляет специальные API, которые автоматически очищают ресурсы, когда они покидают экран или когда приложение переходит в фоновый режим.
Ключевые API:
- Потоки для текущего
Lifecycle.State. LifecycleEffects, который позволяет запустить блок на основе определенногоLifecycle.Event.
Эти интеграции предоставляют удобные хуки для управления жизненными циклами в иерархии Compose. В этом документе рассказывается, как использовать их в приложении.
Как собирать данные о состоянии жизненного цикла с помощью потоков
Lifecycle предоставляет свойство currentStateFlow, которое возвращает текущее значение Lifecycle.State в виде Kotlin StateFlow. Вы можете забрать этот Flow в качестве State. Это позволяет вашему приложению считывать изменения в жизненном цикле во время
композиции.
val lifecycleOwner = LocalLifecycleOwner.current
val stateFlow = lifecycleOwner.lifecycle.currentStateFlow
…
val currentLifecycleState by stateFlow.collectAsState()
Пример выше доступен в модуле lifecycle-common. Метод currentStateAsState() доступен в модуле lifecycle-runtime-compose. Он позволяет легко узнать текущее состояние жизненного цикла с помощью одной строки. Это показано в следующем примере:
val lifecycleOwner = LocalLifecycleOwner.current
val currentLifecycleState = lifecycleOwner.lifecycle.currentStateAsState()
Выполнение кода при событиях жизненного цикла
Вместо того чтобы создавать отдельный класс, реализующий DefaultLifecycleObserver, и вручную добавлять его в жизненный цикл, вы можете объявить логику жизненного цикла встроенной с помощью специальных эффектов. LifecycleEffects позволяет запустить блок, когда в композиции происходит определенное Lifecycle.Event.
LifecycleEventEffect
Используйте LifecycleEventEffect, чтобы запустить блок кода при возникновении определенного события. Это лучше всего подходит для однократных событий, таких как ведение журнала или аналитика, когда не требуется ни успешное выполнение, ни немедленный результат.
@Composable
fun AnalyticsTracker(screenName: String) {
// Log an event when the app receives ON_RESUME (e.g. comes to foreground)
LifecycleEventEffect(Lifecycle.Event.ON_RESUME) {
Analytics.logView(screenName)
}
}
LifecycleStartEffect
Для парных операций запуска и остановки, которые должны выполняться, когда приложение запущено (видимо), и очищаться, когда приложение остановлено (в фоновом режиме), используйте LifecycleStartEffect.
Как и другие эффекты Compose (например, LaunchedEffect), LifecycleStartEffect принимает ключи. Когда ключ меняется, блок запускается снова.
Когда происходит событие Lifecycle.Event.ON_STOP или эффект выходит из композиции, выполняется блок onStopOrDispose, чтобы очистить все, что было частью начального блока.
@Composable
fun LocationMonitor(locationManager: LocationManager) {
// Starts monitoring when ON_START is dispatched
// Stops monitoring when ON_STOP is dispatched
// (or the composable leaves the screen)
LifecycleStartEffect(locationManager) {
val listener = LocationListener { location ->
/* update UI */
}
locationManager.requestLocationUpdates(listener)
// The cleanup block automatically runs on ON_STOP or on disposal
onStopOrDispose {
locationManager.removeUpdates(listener)
}
}
}
Информацию о других типах побочных эффектов можно найти в статье Побочные эффекты в Compose.
LifecycleResumeEffect
LifecycleResumeEffect работает так же, как и LifecycleStartEffect, но привязан к событию Lifecycle.Event.ON_RESUME. Он также предоставляет блок onPauseOrDispose, который выполняет очистку при отправке ON_PAUSE или когда composable-функция покидает экран.
Этот API полезен для ресурсов, которые должны быть активны, только когда пользователь взаимодействует с приложением, например для камер или анимации.
@Composable
fun CameraPreview(cameraController: CameraController) {
LifecycleResumeEffect(cameraController) {
cameraController.startPreview()
onPauseOrDispose {
cameraController.stopPreview()
}
}
}
Доступ к LifecycleOwner
В Compose LifecycleOwner неявно доступен через CompositionLocal с именем LocalLifecycleOwner. По умолчанию владельцем является корневой хост иерархии композиции.
val lifecycleOwner = LocalLifecycleOwner.current
Для многих приложений достаточно проверить этого владельца по умолчанию или передать его эффектам, учитывающим жизненный цикл. Однако для пользовательской навигации или сложных макетов может потребоваться создать собственный LifecycleOwner, чтобы ограничить состояния жизненного цикла определенными разделами пользовательского интерфейса. Например, библиотеки навигации (такие как Navigation 3) делают это автоматически, чтобы у каждого отдельного экрана был свой жизненный цикл.
Создание пользовательского LifecycleOwner
rememberLifecycleOwner() API позволяет создавать и запоминать пользовательские LifecycleOwner. Это особенно полезно для таких компонентов, как HorizontalPager, когда нужно, чтобы только видимая страница была RESUMED, а для соседних страниц, которые не видны на экране, задано значение maxState STARTED.
val pagerState = rememberPagerState(pageCount = { 10 })
HorizontalPager(state = pagerState) { pageNum ->
val pageLifecycleOwner = rememberLifecycleOwner(
maxState = if (pagerState.settledPage == pageNum) {
Lifecycle.State.RESUMED
} else {
Lifecycle.State.STARTED
}
)
CompositionLocalProvider(LocalLifecycleOwner provides pageLifecycleOwner) {
// Your pages here. Their lifecycle-aware components respect the
// custom maxState defined above.
}
}
Дополнительную информацию о CompositionLocal можно найти в статье Локальные данные с CompositionLocal.
Рекомендации по работе с компонентами, учитывающими жизненный цикл
- Контроллеры пользовательского интерфейса должны быть как можно более простыми. Они не должны пытаться получить собственные данные. Вместо этого используйте
ViewModelи наблюдайте за объектомStateFlow, чтобы отразить изменения в пользовательском интерфейсе. - Попробуйте написать пользовательские интерфейсы, управляемые данными, в которых контроллер пользовательского интерфейса отвечает за обновление пользовательского интерфейса по мере изменения данных или уведомляет о действиях пользователя обратно в
ViewModel. - Поместите логику данных в класс
ViewModel.ViewModelдолжен служить связующим звеном между контроллером пользовательского интерфейса и остальной частью приложения. Однако будьте осторожны:ViewModelне отвечает за получение данных (например, из сети). Вместо этогоViewModelдолжен вызывать соответствующий компонент для получения данных, а затем передавать результат обратно контроллеру пользовательского интерфейса. - Используйте сопрограммы Kotlin для управления длительными задачами и другими операциями, которые могут выполняться асинхронно.
- Логика запуска и остановки должна находиться внутри composable-функции, которой она действительно нужна. Таким образом, логика автоматически удаляется, если этот конкретный элемент пользовательского интерфейса удаляется с экрана (например, внутри графа навигации или когда видимость является условной).
- Используйте
collectAsStateWithLifecycleдля передачи данных. Не запускайте и не останавливайте сбор данныхFlowвручную на основе событий жизненного цикла. Вместо этого используйтеcollectAsStateWithLifecycle, чтобы эффективно преобразовывать потоки в состояние пользовательского интерфейса. Это позволяет экономить заряд батареи и ресурсы, посколькуFlowприостанавливаются, когда приложение работает в фоновом режиме.
Подробнее о Flow читайте в разделе Другие поддерживаемые типы состояния.
Примеры использования компонентов с учетом жизненного цикла
Компоненты, учитывающие жизненный цикл, могут значительно упростить управление жизненными циклами в различных случаях. Вот несколько примеров:
- Переключение между приблизительными и точными уведомлениями о местоположении. Используйте
LifecycleStartEffect, чтобы включить точное определение местоположения, когда приложение открыто (ON_START), и автоматически отключить слушатель или переключиться на приблизительное определение местоположения, когда приложение работает в фоновом режиме (ON_STOP). - Остановка и запуск буферизации видео. Используйте
LifecycleResumeEffect, чтобы отложить воспроизведение видео до тех пор, пока приложение не будет полностью открыто на переднем плане и не станет интерактивным (ON_RESUME), а также чтобы приостановить воспроизведение и освободить ресурсы, когда приложение работает в фоновом режиме (ON_PAUSE). - Запуск и остановка сетевой трансляции. Используйте
collectAsStateWithLifecycle, чтобы наблюдать за непрерывными потоками данных (например, Kotlin Flow из сетевого сокета). Это позволяет получать обновления в реальном времени, когда приложение активно, и автоматически отменять сбор данных, когда оно работает в фоновом режиме. - Приостановка и возобновление ресурсоемких задач. Используйте
LifecycleResumeEffect, чтобы приостанавливать ресурсоемкие визуальные обновления, когда приложение работает в фоновом режиме, и возобновлять их, когда оно переходит в активный режим.
Безопасная обработка событий ON_STOP
Compose безопасно обрабатывает события ON_STOP.
- Состояние безопасно. Вы можете в любой момент обновить
MutableState(например, с помощьюuiState.value = ...), даже если приложение работает в фоновом режиме. Compose ждет, пока приложение станет видимым, чтобы отобразить изменения. - Автоматическая очистка. При использовании таких эффектов, как
LifecycleStartEffect, блок очистки (onStopOrDispose) запускается точно в момент перехода жизненного цикла в состояниеSTOPPED. Это позволяет избежать удержания тяжелых ресурсов (например, камеры или местоположения), когда приложение находится в фоновом режиме.
Подробнее MutableState и состоянии в Jetpack Compose…
Дополнительные ресурсы
Дополнительную информацию об управлении жизненными циклами с помощью компонентов, учитывающих жизненный цикл, можно найти в следующих ресурсах.
Просмотр контента
Рекомендуем
- Примечание. Текст ссылки показывается, когда JavaScript отключен.
- Обзор LiveData
- Как использовать сопрограммы Kotlin с компонентами, учитывающими жизненный цикл
- Модуль Saved State для ViewModel