lifecycleScope — это встроенный CoroutineScope из библиотеки androidx.lifecycle, который привязан к жизненному циклу Activity, Fragment или любого LifecycleOwner и автоматически отменяет корутины при уничтожении компонента. По данным Google Android Developers, 2025, lifecycleScope позволяет безопасно запускать корутины, связанные с UI-слоем, без риска выполнить код после уничтожения Activity или Fragment. scope автоматически отменяется при переходе LifecycleOwner в состояние DESTROYED.
Главное
lifecycleScope — это extension-свойство на интерфейс LifecycleOwner (Activity, Fragment, Service), предоставляющее готовый CoroutineScope, привязанный к полному жизненному циклу компонента. Когда LifecycleOwner достигает состояния DESTROYED, lifecycleScope автоматически отменяет все активные корутины.
// In Fragment or Activity
lifecycleScope.launch {
delay(1000)
showSnackbar("Hello!")
}
В отличие от viewModelScope, lifecycleScope отменяется при каждом уничтожении LifecycleOwner — включая ротацию экрана. Это делает его идеальным для операций, которые должны жить только пока виден конкретный экран.
lifecycleScope доступен везде, где есть LifecycleOwner:
Механизм автоматической отмены lifecycleScope основан на подписке на события Lifecycle. Когда Lifecycle опускается ниже CREATED в DESTROYED, scope отменяется.
| Состояние | Описание | Scope активен |
|---|---|---|
| CREATED | LifecycleOwner создан, onCreate выполнен | Да |
| STARTED | LifecycleOwner видим (onStart) | Да |
| RESUMED | LifecycleOwner на переднем плане (onResume) | Да |
| DESTROYED | LifecycleOwner уничтожен (onDestroy) | Нет (scope отменён) |
lifecycleScope создаётся как CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) и хранится внутри Lifecycle. При переходе Lifecycle в состояние DESTROYED вызывается scope.cancel(). Механизм реализован через LifecycleEventObserver, который подписывается на события жизненного цикла при первом обращении к scope.
При повороте экрана Activity уничтожается (onDestroy) и создаётся заново. lifecycleScope отменяется вместе со старой Activity, и новый экземпляр scope создаётся для новой Activity. Это принципиальное отличие от viewModelScope, который сохраняется при ротации.
Библиотека lifecycle предоставляет несколько способов запуска корутин через lifecycleScope. Рассмотрим эволюцию API от устаревших методов к современным.
Самый простой способ — lifecycleScope.launch { ... }. Корутина запускается немедленно и отменяется при DESTROYED. Однако она может выполнять код даже когда UI невидим (например, в фоне после onStop). Это не всегда желательно.
Эти методы приостанавливали выполнение корутины, когда Lifecycle опускался ниже указанного состояния, и возобновляли при возврате. Однако они были помечены как @Deprecated в lifecycle-runtime-ktx 2.6.0, потому что:
repeatOnLifecycle — рекомендованный Google способ запуска корутин, синхронизированных с жизненным циклом. Он отменяет и перезапускает корутину каждый раз, когда Lifecycle достигает заданного состояния.
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { state ->
updateUI(state)
}
}
}
Корутина, переданная в repeatOnLifecycle, запускается когда Lifecycle достигает STARTED, и отменяется когда он опускается ниже STARTED. При возврате в STARTED корутина перезапускается заново. Это безопасно и эффективно — никакие корутины не висят в паузе.
Для сбора данных из Flow с учётом жизненного цикла существует оператор flowWithLifecycle. Он автоматически останавливает и возобновляет сбор при изменении состояния Lifecycle:
viewModel.uiState
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
.onEach { state -> updateUI(state) }
.launchIn(lifecycleScope)
Оператор flowWithLifecycle — наиболее лаконичный способ безопасной подписки на Flow в UI-слое.
Рассмотрим три реальных сценария применения lifecycleScope в Android-приложении на Kotlin.
class MapFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
locationProvider.observeLocation().collect { loc ->
updateMapMarker(loc)
}
}
}
}
}
Корутина стартует когда фрагмент становится видимым (STARTED) и отменяется когда он уходит с экрана (STOPPED). Если пользователь переключается на другое приложение, Location-обновления не потребляют батарею.
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
animateFadeIn(titleView)
delay(200)
animateSlideUp(contentView)
}
}
Анимация запускается только когда фрагмент на переднем плане (RESUMED). Если пользователь сворачивает приложение во время анимации, корутина отменяется, и при возврате анимация запускается заново.
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
while (isActive) {
syncData()
delay(30_000L)
}
}
}
Данные синхронизируются каждые 30 секунд, но только когда экран видим. isActive проверяет, не отменена ли корутина, что обеспечивает возможность безопасного выхода из цикла при уходе с экрана.
Оба scope привязаны к жизненному циклу, но к разным его аспектам. Понимание разницы критически важно для правильной архитектуры Android-приложений.
viewModelScope привязан к ViewModel, которая переживает ротацию экрана. lifecycleScope привязан к LifecycleOwner (Activity/Fragment), который при ротации уничтожается и создаётся заново. Это определяет сценарии их применения.
На практике часто встречается комбинация обоих scope: viewModelScope загружает данные и управляет состоянием, lifecycleScope подписывается на Flow из ViewModel с учётом жизненного цикла экрана. Это разделение ответственности считается best practice в современной Android-разработке.
Рассмотрим четыре наиболее частые ошибки, которые допускают разработчики при использовании lifecycleScope.
Если запустить загрузку данных в lifecycleScope.launch, при ротации экрана корутина отменится, и данные придётся загружать заново. Используйте viewModelScope для долгоживущих операций. lifecycleScope — только для UI-привязанных задач.
Прямой вызов viewModel.someFlow.collect { ... } внутри lifecycleScope.launch продолжает собирать данные даже когда экран невидим. Это может привести к обновлению UI в фоне и лишним накладным расходам. Всегда используйте repeatOnLifecycle или flowWithLifecycle.
Хотя lifecycleScope отменяется при DESTROYED, код после точки приостановки (suspend) может не выполниться при внезапной отмене. Не полагайтесь на выполнение post-кода после suspend-вызова, если только не используете NonCancellable.
launchWhenStarted и его аналоги не отменяют корутину, а только приостанавливают. Если экран много раз переключается между передним и задним планом, корутина накапливает отложенные вызовы. Переходите на repeatOnLifecycle — это единственный правильный способ синхронизации с Lifecycle.
Часто задаваемые вопросы
lifecycleScope автоматически отменяется при уничтожении LifecycleOwner. GlobalScope живёт всё время работы приложения. Корутина в lifecycleScope не может обновлять UI после уничтожения компонента, в GlobalScope — может, что приводит к падениям. Всегда используйте lifecycleScope в UI-слое.
Нет, ViewModel не является LifecycleOwner, поэтому lifecycleScope в ней недоступен. ViewModel использует viewModelScope. Если код должен выполняться в обоих контекстах — вынесите логику в use case или repository с suspend-функциями.
Каждый вызов repeatOnLifecycle создаёт новую корутину, которая запускает блок при достижении указанного состояния Lifecycle. Если вызвать repeatOnLifecycle дважды для одного состояния, оба блока будут запущены независимо. Обычно достаточно одного вызова в onViewCreated.
Непосредственно изменить диспетчер lifecycleScope нельзя — он использует Dispatchers.Main.immediate. Внутри блока корутины можно переключиться на другой диспетчер через withContext. Для тестов используйте TestDispatcher с LifecycleOwner.
lifecycleScope отменяется при переходе LifecycleOwner в состояние DESTROYED (после onDestroy). Простые вызовы lifecycleScope.launch не отменяются в onPause или onStop. Для паузы при уходе в фон используйте repeatOnLifecycle(STARTED) или repeatOnLifecycle(RESUMED).
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также