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 vs 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 vs viewModelScope — lifecycleScope за UI операције (анимације, локација), viewModelScope за податке и пословну логику
  • Ротација екрана — lifecycleScope се отказује при ротацији, viewModelScope се чува; бирајте scope у зависности од задатка

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође