lifecycleScope — какво е, свързване с Lifecycle и работа в Android

Автор: IT Sectr Публикувано: 2026-06-23 Време за четене: 9 мин

lifecycleScope — е вграден CoroutineScope от библиотеката androidx.lifecycle, който е свързан с жизнения цикъл на Activity, Fragment или всеки LifecycleOwner и автоматично отменя корутините при унищожаване на компонента. Според Google Android Developers, 2025, lifecycleScope позволява безопасно стартиране на корутини, свързани с UI слоя, без риск от изпълнение на код след унищожаване на Activity или Fragment. Scope автоматично се отменя при преминаване на LifecycleOwner в състояние DESTROYED.

Основни точки

  • lifecycleScope — CoroutineScope от lifecycle-runtime-ktx, отменян в състояние DESTROYED на Lifecycle
  • lifecycleScope.launch — стартиране на корутина, която автоматично се отменя при унищожаване на LifecycleOwner
  • launchWhenStarted / launchWhenResumed — остарели методи, заменени с repeatOnLifecycle
  • repeatOnLifecycle — модерен API за стартиране на корутини, следващи конкретно състояние на Lifecycle
  • Dispatchers.Main.immediate — диспечер по подразбиране за lifecycleScope

Какво е lifecycleScope в Android?

lifecycleScope — е разширяващо свойство на интерфейса LifecycleOwner (Activity, Fragment, Service), което предоставя готов CoroutineScope, свързан с пълния жизнен цикъл на компонента. Когато LifecycleOwner достигне състояние DESTROYED, lifecycleScope автоматично отменя всички активни корутини.

kotlin
// В Fragment или Activity
lifecycleScope.launch {
    delay(1000)
    showSnackbar("Здравейте!")
}

За разлика от viewModelScope, lifecycleScope се отменя при всяко унищожаване на LifecycleOwner — включително завъртане на екрана. Това го прави идеален за операции, които трябва да живеят само докато определен екран е видим.

Къде е наличен lifecycleScope

lifecycleScope е наличен навсякъде, където има LifecycleOwner:

  • Activity — AppCompatActivity наследява LifecycleOwner
  • Fragment — Fragment наследява LifecycleOwner
  • LifecycleService — услуга с жизнен цикъл
  • ProcessLifecycleOwner — жизнен цикъл на цялото приложение
  • Персонализиран LifecycleOwner — всички обекти, имплементиращи LifecycleOwner

Как работи lifecycleScope: Lifecycle и автоматично отменяне

Механизмът за автоматично отменяне на lifecycleScope се основава на абонамент за събития на Lifecycle. Когато Lifecycle падне под CREATED до DESTROYED, scope се отменя.

Състояния на Lifecycle

СъстояниеОписаниеScope активен
CREATEDLifecycleOwner създаден, onCreate изпълненДа
STARTEDLifecycleOwner видим (onStart)Да
RESUMEDLifecycleOwner на преден план (onResume)Да
DESTROYEDLifecycleOwner унищожен (onDestroy)Не (scope отменен)

Вътрешна структура на lifecycleScope

lifecycleScope се създава като CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) и се съхранява вътре в Lifecycle. При преминаване на Lifecycle в състояние DESTROYED се извиква scope.cancel(). Механизмът е имплементиран чрез LifecycleEventObserver, който се абонира за събития на жизнения цикъл при първия достъп до scope.

Поведение при завъртане

При завъртане на екрана Activity се унищожава (onDestroy) и се създава отново. lifecycleScope се отменя заедно със старата Activity и нова инстанция на scope се създава за новата Activity. Това е фундаментална разлика от viewModelScope, който се запазва при завъртане.

API на lifecycleScope: launch, launchWhen и repeatOnLifecycle

Библиотеката lifecycle предоставя няколко начина за стартиране на корутини чрез lifecycleScope. Нека разгледаме еволюцията на API от остарели методи към модерни.

lifecycleScope.launch — основно стартиране

Най-простият начин — lifecycleScope.launch { ... }. Корутината стартира незабавно и се отменя при DESTROYED. Тя обаче може да изпълнява код дори когато UI не е видим (напр. на заден план след onStop). Това не винаги е желателно.

Остарели: launchWhenCreated / launchWhenStarted / launchWhenResumed

Тези методи спираха изпълнението на корутината, когато Lifecycle падне под определеното състояние, и го възобновяваха при връщане. Те обаче бяха маркирани като @Deprecated в lifecycle-runtime-ktx 2.6.0, защото:

  • Не отменяха корутината — само я спираха
  • Водеха до натрупване на висящи корутини, консумиращи памет
  • Създаваха race condition при бързо превключване на състояния

Модерен API: repeatOnLifecycle

repeatOnLifecycle — препоръчваният от Google начин за стартиране на корутини, синхронизирани с жизнения цикъл. Той отменя и рестартира корутината всеки път, когато Lifecycle достигне определено състояние.

kotlin
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.uiState.collect { state ->
            updateUI(state)
        }
    }
}

Корутината, предадена на repeatOnLifecycle, стартира когато Lifecycle достигне STARTED и се отменя когато падне под STARTED. При връщане към STARTED корутината се рестартира отначало. Това е безопасно и ефективно — никакви корутини не висят в пауза.

flowWithLifecycle — за Flow

За събиране на данни от Flow с оглед на жизнения цикъл съществува оператор flowWithLifecycle. Той автоматично спира и възобновява събирането при промяна на състоянието на Lifecycle:

kotlin
viewModel.uiState
    .flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
    .onEach { state -> updateUI(state) }
    .launchIn(lifecycleScope)

Операторът flowWithLifecycle — най-краткият начин за безопасен абонамент за Flow в UI слоя.

Примери за използване на lifecycleScope

Нека разгледаме три реални сценария за използване на lifecycleScope в Android приложение на Kotlin.

Пример 1: Абонамент за актуализации на местоположение само когато екранът е видим

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). Ако потребителят превключи към друго приложение, актуализациите на местоположение не консумират батерия.

Пример 2: Стартиране на анимация при стартиране на фрагмент

kotlin
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.RESUMED) {
        animateFadeIn(titleView)
        delay(200)
        animateSlideUp(contentView)
    }
}

Анимацията стартира само когато фрагментът е на преден план (RESUMED). Ако потребителят минимизира приложението по време на анимация, корутината се отменя и при връщане анимацията се рестартира.

Пример 3: Периодична синхронизация на данни на видим екран

kotlin
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        while (isActive) {
            syncData()
            delay(30_000L)
        }
    }
}

Данните се синхронизират на всеки 30 секунди, но само когато екранът е видим. isActive проверява дали корутината не е отменена, което осигурява безопасно излизане от цикъла при напускане на екрана.

lifecycleScope срещу viewModelScope: сценарии на приложение

И двата scope са свързани с жизнения цикъл, но с различни негови аспекти. Разбирането на разликата е критично за правилната архитектура на Android приложения.

Ключова разлика

viewModelScope е свързан с ViewModel, който оцелява при завъртане на екрана. lifecycleScope е свързан с LifecycleOwner (Activity/Fragment), който при завъртане се унищожава и създава отново. Това определя сценариите на тяхното приложение.

Кога да използваме lifecycleScope

  • Абонамент за системни събития (местоположение, сензори, камера)
  • Анимации и UI ефекти, свързани с конкретен екран
  • Поетапно зареждане на данни с оглед на видимостта на екрана
  • Операции, които трябва да спрат при напускане на екрана

Кога да използваме viewModelScope

  • Зареждане на данни от Repository
  • Бизнес логика, която трябва да оцелее при завъртане
  • Кеширане и обработка на данни
  • Всички операции, чийто резултат е необходим след завъртане

Комбинирано използване

На практика комбинацията от двата scope често се среща: viewModelScope зарежда данни и управлява състоянието, lifecycleScope се абонира за Flow от ViewModel с оглед на жизнения цикъл на екрана. Това разделение на отговорностите се счита за best practice в съвременното Android разработване.

Типични грешки при работа с lifecycleScope

Нека разгледаме четирите най-чести грешки, които разработчиците допускат при използване на lifecycleScope.

Грешка 1: Използване на lifecycleScope вместо viewModelScope за зареждане на данни

Ако стартирате зареждане на данни в lifecycleScope.launch, при завъртане на екрана корутината ще бъде отменена и данните ще трябва да се заредят отново. Използвайте viewModelScope за дълготрайни операции. lifecycleScope — само за задачи, свързани с UI.

Грешка 2: Събиране на Flow без repeatOnLifecycle

Директното извикване на viewModel.someFlow.collect { ... } вътре в lifecycleScope.launch продължава да събира данни дори когато екранът не е видим. Това може да доведе до актуализации на UI на заден план и излишни разходи. Винаги използвайте repeatOnLifecycle или flowWithLifecycle.

Грешка 3: Забравяне на отменянето при напускане на екрана

Въпреки че lifecycleScope се отменя при DESTROYED, кодът след точка на спиране (suspend) може да не се изпълни при внезапно отменяне. Не разчитайте на изпълнение на код след suspend извикване, освен ако не използвате NonCancellable.

Грешка 4: Използване на остарелия launchWhenStarted вместо repeatOnLifecycle

launchWhenStarted и неговите аналози не отменят корутината, само я спират. Ако екранът превключва многократно между преден и заден план, корутината натрупва отложени извиквания. Преминете към repeatOnLifecycle — това е единственият правилен начин за синхронизация с Lifecycle.

Често задавани въпроси

Каква е разликата между lifecycleScope и GlobalScope?

lifecycleScope се отменя автоматично при унищожаване на LifecycleOwner. GlobalScope живее през цялото време на работа на приложението. Корутината в lifecycleScope не може да актуализира UI след унищожаване на компонента, в GlobalScope може, което води до сривове. Винаги използвайте lifecycleScope в UI слоя.

Може ли lifecycleScope да се използва в ViewModel?

Не, ViewModel не е LifecycleOwner, затова lifecycleScope не е достъпен в него. ViewModel използва viewModelScope. Ако кодът трябва да се изпълнява и в двата контекста — извлечете логиката в use case или repository с suspend функции.

Какво се случва при повторно извикване на repeatOnLifecycle?

Всяко извикване на repeatOnLifecycle създава нова корутина, която стартира блок при достигане на определеното състояние на Lifecycle. Ако repeatOnLifecycle се извика два пъти за едно и също състояние, и двата блока ще се изпълнят независимо. Обикновено едно извикване в onViewCreated е достатъчно.

Може ли да се зададе персонализиран Dispatcher за lifecycleScope?

Диспечерът на lifecycleScope не може да се промени директно — той използва Dispatchers.Main.immediate. Вътре в блока на корутината можете да превключите на друг диспечер чрез withContext. За тестове използвайте TestDispatcher с LifecycleOwner.

Отменя ли се lifecycleScope в onPause или onDestroy?

lifecycleScope се отменя при преминаване на LifecycleOwner в състояние DESTROYED (след onDestroy). Обикновените извиквания на lifecycleScope.launch не се отменят в onPause или onStop. За пауза при преминаване на заден план използвайте repeatOnLifecycle(STARTED) или repeatOnLifecycle(RESUMED).

Обобщение

  • lifecycleScope — CoroutineScope, свързан с LifecycleOwner, автоматично отменен при DESTROYED чрез LifecycleEventObserver
  • Dispatchers.Main.immediate — диспечер по подразбиране, осигуряващ безопасно актуализиране на UI без излишни превключвания
  • repeatOnLifecycle — модерен API за стартиране на корутини в определено състояние на Lifecycle с автоматично отменяне и рестартиране
  • flowWithLifecycle — оператор за безопасно събиране на Flow от UI с оглед на жизнения цикъл
  • launchWhenStarted е остарял — вместо спиране използвайте repeatOnLifecycle, който отменя корутината, а не я спира
  • lifecycleScope срещу viewModelScope — lifecycleScope за UI операции (анимации, местоположение), viewModelScope за данни и бизнес логика
  • Завъртане на екрана — lifecycleScope се отменя при завъртане, viewModelScope се запазва; изберете scope в зависимост от задачата

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също