lifecycleScope — este un CoroutineScope încorporat din biblioteca androidx.lifecycle, care este legat de ciclul de viață al Activity, Fragment sau oricărui LifecycleOwner și anulează automat corutinele la distrugerea componentului. Conform Google Android Developers, 2025, lifecycleScope permite lansarea sigură a corutinelor legate de stratul UI fără riscul de a executa cod după distrugerea Activity sau Fragment. Scope se anulează automat la trecerea LifecycleOwner în starea DESTROYED.
Principalele
lifecycleScope — este o proprietate de extensie pe interfața LifecycleOwner (Activity, Fragment, Service) care oferă un CoroutineScope gata făcut, legat de ciclul complet de viață al componentului. Când LifecycleOwner ajunge la starea DESTROYED, lifecycleScope anulează automat toate corutinele active.
// În Fragment sau Activity
lifecycleScope.launch {
delay(1000)
showSnackbar("Salut!")
}
Spre deosebire de viewModelScope, lifecycleScope se anulează la fiecare distrugere a LifecycleOwner — inclusiv la rotirea ecranului. Acest lucru îl face ideal pentru operațiile care trebuie să trăiască doar cât timp un ecran specific este vizibil.
lifecycleScope este disponibil oriunde există LifecycleOwner:
Mecanismul de anulare automată a lifecycleScope se bazează pe abonarea la evenimentele Lifecycle. Când Lifecycle coboară sub CREATED la DESTROYED, scope este anulat.
| Stare | Descriere | Scope activ |
|---|---|---|
| CREATED | LifecycleOwner creat, onCreate executat | Da |
| STARTED | LifecycleOwner vizibil (onStart) | Da |
| RESUMED | LifecycleOwner în prim-plan (onResume) | Da |
| DESTROYED | LifecycleOwner distrus (onDestroy) | Nu (scope anulat) |
lifecycleScope este creat ca CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) și stocat în interiorul Lifecycle. La trecerea Lifecycle în starea DESTROYED este apelat scope.cancel(). Mecanismul este implementat prin LifecycleEventObserver, care se abonează la evenimentele ciclului de viață la prima accesare a scope.
La rotirea ecranului, Activity este distrus (onDestroy) și recreat. lifecycleScope este anulat împreună cu Activity veche și o nouă instanță a scope este creată pentru noua Activity. Aceasta este o diferență fundamentală față de viewModelScope, care se păstrează la rotire.
Biblioteca lifecycle oferă mai multe moduri de a lansa corutine prin lifecycleScope. Să analizăm evoluția API de la metodele învechite la cele moderne.
Cea mai simplă modalitate — lifecycleScope.launch { ... }. Corutina se lansează imediat și se anulează la DESTROYED. Totuși, poate executa cod chiar și când UI nu este vizibil (de exemplu, în fundal după onStop). Acest lucru nu este întotdeauna de dorit.
Aceste metode suspendau execuția corutinei când Lifecycle cobora sub starea specificată și o reluau la revenire. Însă au fost marcate ca @Deprecated în lifecycle-runtime-ktx 2.6.0, deoarece:
repeatOnLifecycle — modul recomandat de Google pentru lansarea corutinelor sincronizate cu ciclul de viață. Anulează și repornește corutina de fiecare dată când Lifecycle atinge o stare specificată.
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { state ->
updateUI(state)
}
}
}
Corutina transmisă în repeatOnLifecycle se lansează când Lifecycle atinge STARTED și se anulează când coboară sub STARTED. La revenirea în STARTED, corutina se repornește de la început. Acest lucru este sigur și eficient — nicio corutină nu rămâne suspendată.
Pentru colectarea datelor din Flow cu luarea în considerare a ciclului de viață există operatorul flowWithLifecycle. Acesta oprește și reia automat colectarea la schimbarea stării Lifecycle:
viewModel.uiState
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
.onEach { state -> updateUI(state) }
.launchIn(lifecycleScope)
Operatorul flowWithLifecycle — cel mai concis mod de abonare sigură la Flow în stratul UI.
Să analizăm trei scenarii reale de aplicare a lifecycleScope într-o aplicație Android în 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)
}
}
}
}
}
Corutina pornește când fragmentul devine vizibil (STARTED) și se anulează când părăsește ecranul (STOPPED). Dacă utilizatorul comută pe altă aplicație, actualizările de locație nu consumă bateria.
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
animateFadeIn(titleView)
delay(200)
animateSlideUp(contentView)
}
}
Animația se lansează doar când fragmentul este în prim-plan (RESUMED). Dacă utilizatorul minimizează aplicația în timpul animației, corutina este anulată, iar la revenire animația se lansează din nou.
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
while (isActive) {
syncData()
delay(30_000L)
}
}
}
Datele sunt sincronizate la fiecare 30 de secunde, dar doar când ecranul este vizibil. isActive verifică dacă corutina nu a fost anulată, asigurând ieșirea sigură din buclă la părăsirea ecranului.
Ambele scope sunt legate de ciclul de viață, dar de aspecte diferite ale acestuia. Înțelegerea diferenței este critică pentru arhitectura corectă a aplicațiilor Android.
viewModelScope este legat de ViewModel, care supraviețuiește rotirii ecranului. lifecycleScope este legat de LifecycleOwner (Activity/Fragment), care la rotire este distrus și recreat. Aceasta determină scenariile de aplicare.
În practică, combinația ambelor scope este frecventă: viewModelScope încarcă datele și gestionează starea, lifecycleScope se abonează la Flow din ViewModel cu luarea în considerare a ciclului de viață al ecranului. Această separare a responsabilităților este considerată best practice în dezvoltarea modernă Android.
Să analizăm patru dintre cele mai frecvente erori pe care le fac dezvoltatorii la utilizarea lifecycleScope.
Dacă lansați încărcarea datelor în lifecycleScope.launch, la rotirea ecranului corutina va fi anulată și datele vor trebui reîncărcate. Utilizați viewModelScope pentru operații de lungă durată. lifecycleScope — doar pentru sarcini legate de UI.
Apelul direct viewModel.someFlow.collect { ... } în interiorul lifecycleScope.launch continuă să colecteze date chiar și când ecranul nu este vizibil. Acest lucru poate duce la actualizări UI în fundal și costuri suplimentare. Folosiți întotdeauna repeatOnLifecycle sau flowWithLifecycle.
Deși lifecycleScope se anulează la DESTROYED, codul de după punctul de suspendare (suspend) poate să nu se execute la anularea bruscă. Nu vă bazați pe executarea codului după un apel suspend, decât dacă folosiți NonCancellable.
launchWhenStarted și analogii săi nu anulează corutina, ci doar o suspendă. Dacă ecranul comută de mai multe ori între prim-plan și fundal, corutina acumulează apeluri amânate. Migrați la repeatOnLifecycle — acesta este singurul mod corect de sincronizare cu Lifecycle.
Întrebări frecvente
lifecycleScope se anulează automat la distrugerea LifecycleOwner. GlobalScope trăiește pe tot timpul de funcționare a aplicației. Corutina în lifecycleScope nu poate actualiza UI după distrugerea componentului, în GlobalScope — poate, ceea ce duce la erori. Folosiți întotdeauna lifecycleScope în stratul UI.
Nu, ViewModel nu este LifecycleOwner, deci lifecycleScope nu este disponibil în el. ViewModel folosește viewModelScope. Dacă codul trebuie executat în ambele contexte — extrăgeți logica în use case sau repository cu funcții suspend.
Fiecare apel repeatOnLifecycle creează o nouă corutină care lansează blocul la atingerea stării specificate Lifecycle. Dacă repeatOnLifecycle este apelat de două ori pentru aceeași stare, ambele blocuri vor fi lansate independent. De obicei, un singur apel în onViewCreated este suficient.
Nu se poate schimba direct dispecerul lifecycleScope — acesta folosește Dispatchers.Main.immediate. În interiorul blocului corutinei puteți comuta pe un alt dispecer prin withContext. Pentru teste, utilizați TestDispatcher cu LifecycleOwner.
lifecycleScope se anulează la trecerea LifecycleOwner în starea DESTROYED (după onDestroy). Apelurile simple lifecycleScope.launch nu se anulează în onPause sau onStop. Pentru pauză la trecerea în fundal, folosiți repeatOnLifecycle(STARTED) sau repeatOnLifecycle(RESUMED).
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și