LifecycleOwner — este o interfață cheie din biblioteca Android Jetpack care declară că un obiect are un ciclu de viață și oferă acces la acesta prin metoda getLifecycle(). Stă la baza arhitecturii componentelor aplicațiilor Android moderne, permițând separarea logicii de lucru cu ciclul de viață de implementarea concretă a Activity sau Fragment. Conform datelor Google I/O 2024, peste 85% dintre proiectele noi pe Android folosesc LifecycleOwner pentru gestionarea abonamentelor și prevenirea scurgerilor de memorie. Această interfață este fundamentul pentru LiveData, ViewModel și alte componente Jetpack, asigurând executarea sigură a codului numai în starea activă a componentei.
Principalele puncte
LifecycleOwner — este o interfață din pachetul androidx.lifecycle care conține o singură metodă getLifecycle(), ce returnează un obiect Lifecycle. Acest obiect urmărește starea curentă a componentei (CREATED, STARTED, RESUMED, DESTROYED) și notifică toți observatorii abonați la modificarea acesteia. LifecycleOwner face parte din Architecture Components și intră în biblioteca lifecycle-runtime.
Sarcina principală a interfeței este standardizarea accesului la ciclul de viață. Înainte de apariția Jetpack, dezvoltatorii foloseau abonarea manuală în onStart și dezabonarea în onStop, ceea ce ducea la duplicarea codului și erori. LifecycleOwner rezolvă această problemă oferind un mecanism unic pentru toate componentele Android. În locul apelării explicite a metodelor ciclului de viață, dezvoltatorul se abonează o dată la Lifecycle, iar notificările vin automat.
Interfața este declarată în Kotlin ca interfață funcțională cu o singură metodă abstractă:
interface LifecycleOwner {
val lifecycle: Lifecycle
}
Datorită caracterului funcțional al interfeței, este ușor de implementat cu ajutorul unui delegat sau lambda. Acest lucru este deosebit de convenabil pentru crearea de Custom Views și clase ViewModel care trebuie să reacționeze la modificările ciclului de viață al gazdei. Obiectul Lifecycle obținut din getLifecycle() oferă metodele addObserver și removeObserver pentru gestionarea abonamentelor.
LifecycleOwner funcționează în combinație cu două clase cheie: Lifecycle și LifecycleObserver. Lifecycle stochează starea curentă a componentei sub formă de enum State (INITIALIZED, CREATED, STARTED, RESUMED, DESTROYED) și urmărește tranzițiile între ele. Când starea se modifică, Lifecycle notifică toți observatorii înregistrați, apelând metodele adnotate corespunzătoare. Acest mecanism se numește „lifecycle-aware" — codul se execută numai atunci când componenta se află în starea potrivită.
Mecanismul de transmitere a evenimentelor se bazează pe modelul Observer. LifecycleOwner joacă rolul de Observable, iar implementarea LifecycleObserver — rolul de Observer. Activity sau Fragment, la modificarea stării sale (onCreate → onStart → onResume → onPause → onStop → onDestroy), notifică Lifecycle prin mecanismul intern ReportFragment, care este adăugat automat în sistemul AndroidX. Dezvoltatorul nu trebuie să apeleze manual metodele Lifecycle — totul se întâmplă automat.
| Starea Lifecycle | Eveniment | Metoda ciclului de viață Android |
|---|---|---|
| INITIALIZED | — | Înainte de onCreate |
| CREATED | ON_CREATE | onCreate |
| STARTED | ON_START | onStart |
| RESUMED | ON_RESUME | onResume |
| STARTED | ON_PAUSE | onPause |
| CREATED | ON_STOP | onStop |
| DESTROYED | ON_DESTROY | onDestroy |
Un detaliu important: Lifecycle garantează că evenimentele ON_STOP și ON_DESTROY vor fi livrate chiar și în cazul terminării accidentale a procesului. Acest lucru face din LifecycleOwner un instrument de încredere pentru eliberarea resurselor critice. Pentru salvarea obișnuită a stării, se recomandă utilizarea SavedStateHandle în ViewModel, dar LifecycleOwner asigură un nivel de bază de securitate.
Există două moduri de a vă abona la evenimentele LifecycleOwner: clasic LifecycleObserver cu adnotări și modern DefaultLifecycleObserver cu metode explicite. A doua abordare este recomandată de Google din 2022, deoarece oferă o mai bună siguranță a tipurilor și evită reflecția care era utilizată în abordarea cu adnotări. DefaultLifecycleObserver necesită Java 8+ sau Kotlin și este preferat pentru proiectele noi.
Exemplu de abonare prin DefaultLifecycleObserver:
class MyObserver : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
// Pornirea urmăririi GPS numai când componenta este activă
startLocationUpdates()
}
override fun onStop(owner: LifecycleOwner) {
// Oprirea sigură la trecerea în modul fundal
stopLocationUpdates()
}
}
// Conexiune:
lifecycleOwner.lifecycle.addObserver(MyObserver())
Fiecare metodă a DefaultLifecycleObserver primește LifecycleOwner ca parametru. Acest lucru permite observatorului să acceseze contextul componentei în execuție fără a fi nevoie să îl transmită separat. Această abordare face codul mai modular și mai testabil — Observer nu depinde de o implementare concretă a Activity sau Fragment, ci lucrează cu abstractizarea LifecycleOwner.
Metoda veche cu utilizarea adnotării @OnLifecycleEvent încă apare în proiectele moștenite, dar utilizarea sa nu este recomandată pentru codul nou. Reflecția necesară pentru procesarea adnotărilor adaugă overhead și poate duce la erori care nu sunt detectate în faza de compilare. Google recomandă oficial migrarea la DefaultLifecycleObserver.
// Abordare învechită — nerecomandată pentru proiecte noi
class MyLegacyObserver : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onStart() {
startLocationUpdates()
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onStop() {
stopLocationUpdates()
}
}
Abordarea cu adnotări are un dezavantaj semnificativ: lipsa controlului duratei de viață a Observer. Dacă dezvoltatorul uită să dezaboneze Observer la distrugerea LifecycleOwner, obiectul Observer rămâne în memorie până la apelarea colectorului de gunoi. DefaultLifecycleObserver rezolvă această problemă — Observer este legat de Lifecycle și se dezabonează automat la trecerea în starea DESTROYED.
Începând cu AppCompat 1.1.0 și AndroidX Fragment 1.2.0, toate Activity și Fragment care moștenesc AppCompatActivity sau Fragment sunt automat LifecycleOwner. Aceasta înseamnă că metoda getLifecycle() este disponibilă în ele implicit, iar abonarea la evenimentele ciclului de viață funcționează fără configurare suplimentară. Dezvoltatorul trebuie doar să apeleze lifecycle.addObserver() din orice loc al Activity sau Fragment.
Să analizăm un exemplu de integrare LifecycleOwner în Activity:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycle.addObserver(LocationObserver(this))
}
}
În acest exemplu, lifecycle este o extension property disponibilă datorită AndroidX Activity. Observer-ul LocationObserver va primi automat notificări despre pornirea (ON_START) și oprirea (ON_STOP) Activity. La rotirea ecranului, Observer este notificat despre ON_DESTROY și apoi despre ON_CREATE, ceea ce permite gestionarea corectă a modificărilor de configurare fără cod suplimentar.
Fragment implementează LifecycleOwner prin interfață, iar Lifecycle-ul său este legat de ciclul de viață al Fragment, nu de Activity-ul părinte. Acest lucru este important: Lifecycle-ul Fragment trece în DESTROYED când Fragment este eliminat din tranzacție, în timp ce Activity poate rămâne în RESUMED. Această diferență permite Observer să se aboneze separat la ciclul de viață al fiecărei componente.
class MyFragment : Fragment() {
private val uiStateObserver = UiStateObserver()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
lifecycle.addObserver(uiStateObserver)
}
}
Un avantaj important al utilizării LifecycleOwner în Fragment este dezabonarea automată la trecerea Fragment în DESTROYED. Acest lucru este deosebit de relevant pentru ViewPager, unde Fragment-urile pot fi create și distruse dinamic. Gestionarea manuală a abonamentelor în acest scenariu ar fi extrem de complexă și predispusă la erori.
Interfața LifecycleOwner poate fi implementată în orice clasă care are un ciclu de viață. Acest lucru este util pentru Custom Views, Service și chiar ViewModel în unele soluții arhitecturale. Google oferă clasa de ajutor LifecycleRegistry care gestionează starea Lifecycle și generează evenimente. Dezvoltatorul trebuie să apeleze manual metodele corespunzătoare ale LifecycleRegistry la modificarea stării componentei.
Exemplu de implementare LifecycleOwner în Custom View:
class MyCustomView(
context: Context,
attrs: AttributeSet?
) : FrameLayout(context, attrs), LifecycleOwner {
private val lifecycleRegistry = LifecycleRegistry(this)
override val lifecycle: Lifecycle
get() = lifecycleRegistry
fun onStart() {
lifecycleRegistry.setCurrentState(Lifecycle.State.STARTED)
}
fun onStop() {
lifecycleRegistry.setCurrentState(Lifecycle.State.CREATED)
}
}
În acest exemplu, LifecycleRegistry joacă rolul de depozit al stării. Metodele onStart/onStop trebuie apelate de componenta părinte (de exemplu, Activity) când Custom View devine vizibil sau se ascunde. LifecycleRegistry calculează automat evenimentele necesare pentru tranziția între stări și notifică toți Observer-ii abonați.
La implementarea propriului LifecycleOwner, este important să respectați regula: starea LifecycleRegistry trebuie actualizată ultima în metoda corespunzătoare a ciclului de viață, după toate celelalte operații. Acest lucru garantează că Observer-ii vor primi notificarea atunci când componenta este deja complet pregătită pentru noua stare. Utilizarea LifecycleRegistry.createUnsafe ca alternativă este de asemenea posibilă, dar necesită precauție cu firele de execuție.
LifecycleOwner este fundamentul pentru mai multe componente cheie Android Jetpack. LiveData folosește LifecycleOwner pentru a determina starea activă și dezabonarea automată la distrugerea componentei. ViewModel nu implementează direct LifecycleOwner, dar poate primi Lifecycle prin SavedStateHandle. Navigation Component folosește LifecycleOwner pentru gestionarea abonamentelor în NavBackStackEntry. Înțelegerea acestor interconexiuni ajută la construirea arhitecturii aplicației pe o fundație solidă.
Interacțiunea LiveData cu LifecycleOwner:
class ExampleActivity : AppCompatActivity() {
private val viewModel: ExampleViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.userData.observe(this) { data ->
// this — LifecycleOwner (Activity)
// Codul se execută numai când Activity este în starea RESUMED
updateUI(data)
}
}
}
LiveData necesită LifecycleOwner în metoda observe() deoarece garantează că actualizările UI vor avea loc numai în starea activă. Dacă Activity este în fundal, LiveData păstrează ultima valoare, dar nu notifică Observer-ul. La revenirea în RESUMED, Observer primește valoarea actuală fără solicitări suplimentare la rețea sau bază de date.
DataBinding folosește de asemenea LifecycleOwner pentru legarea câmpurilor observable la ciclul de viață al Activity sau Fragment. Acest lucru permite evitarea scurgerilor de memorie în combinația ViewModel + DataBinding — toate abonamentele sunt curățate automat la distrugerea LifecycleOwner. Această abordare face codul declarativ și sigur.
Utilizarea corectă a LifecycleOwner necesită respectarea câtorva reguli cheie. Prima și cea mai importantă: abonați întotdeauna Observer în onCreate/onViewCreated, nu mai târziu. Aceasta garantează că Observer va primi starea inițială a Lifecycle (CREATED după onCreate) și nu va rata evenimente. A doua regulă: folosiți DefaultLifecycleObserver în locul abordării cu adnotări pentru toate proiectele noi.
Abordarea modernă pentru lucrul cu corutine și LifecycleOwner — extensia repeatOnLifecycle:
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.flow.collect { value ->
updateUI(value)
}
}
}
Acest model garantează că collect pe Flow este activă numai în starea STARTED sau RESUMED. La trecerea în STOPPED, colecția este anulată automat, iar la revenirea în STARTED — repornită. repeatOnLifecycle înlocuiește dezabonarea manuală de la Flow în Fragment și este abordarea recomandată de Google pentru lucrul cu fluxuri de date asincrone în componentele UI.
O altă recomandare importantă: nu abuzați de LifecycleObserver pentru logică nelegată de ciclul de viață. Dacă componenta trebuie să execute o acțiune la o anumită stare, dar nu necesită dezabonare la distrugere, este mai bine să folosiți apelarea explicită a metodelor în onStart/onStop. LifecycleObserver este justificat pentru componente de lungă durată (LocationListener, SensorManager), unde gestionarea manuală a abonamentelor este complexă și predispusă la erori.
Întrebări frecvente
LifecycleOwner — este o interfață care declară că un obiect are un ciclu de viață. Lifecycle — este o clasă care stochează starea curentă și gestionează Observer. LifecycleOwner oferă Lifecycle prin getLifecycle().
Nu, Lifecycle dezabonează automat toți Observer-ii la trecerea în DESTROYED. Acesta este unul dintre principalele avantaje ale LifecycleOwner — dezvoltatorul nu trebuie să apeleze manual removeObserver în onDestroy.
Fragment implementează LifecycleOwner prin interfața fragmentelor AndroidX. Lifecycle-ul său este legat de ciclul de viață al Fragment separat de Activity. Acest lucru permite Observer să reacționeze la evenimentele Fragment, nu ale Activity-ului părinte.
Da, pentru aceasta se folosește LifecycleRegistry. Custom View trebuie să implementeze interfața LifecycleOwner și să actualizeze manual starea LifecycleRegistry la modificarea vizibilității sau atașării la fereastră.
LifecycleOwner rezolvă o altă sarcină: gestionarea abonamentelor la evenimentele ciclului de viață, nu anularea corutinelor. Pentru corutine se folosește lifecycleScope, care anulează automat corutinele lansate la distrugerea LifecycleOwner.
Rezumat
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