LifecycleOwner — то је кључни интерфејс из библиотеке Android Jetpack који декларише да објекат поседује животни циклус и пружа приступ њему путем методе getLifecycle(). Он лежи у основи компонентне архитектуре модерних Android апликација, омогућавајући одвајање логике рада са животним циклусом од конкретне имплементације Activity или Fragment. Према подацима Google I/O 2024, више од 85% нових пројеката на Android-у користи LifecycleOwner за управљање претплатама и спречавање цурења меморије. Овај интерфејс је темељ за LiveData, ViewModel и друге Jetpack компоненте, обезбеђујући безбедно извршавање кода само у активном стању компоненте.
Главно
LifecycleOwner — то је интерфејс из пакета androidx.lifecycle који садржи јединствену методу getLifecycle(), која враћа Lifecycle објекат. Овај објекат прати тренутно стање компоненте (CREATED, STARTED, RESUMED, DESTROYED) и обавештава све пријављене посматраче при његовој промени. LifecycleOwner је део Architecture Components и улази у састав библиотеке lifecycle-runtime.
Основни задатак интерфејса је стандардизација приступа животном циклусу. Пре појаве Jetpack-а, програмери су користили ручну претплату у onStart и одјаву у onStop, што је доводило до дуплирања кода и грешака. LifecycleOwner решава овај проблем пружањем јединственог механизма за све Android компоненте. Уместо експлицитног позивања метода животног циклуса, програмер се једном претплаћује на Lifecycle, а обавештења долазе аутоматски.
Интерфејс је декларисан у Kotlin-у као функционални интерфејс са једном апстрактном методом:
interface LifecycleOwner {
val lifecycle: Lifecycle
}
Захваљујући функционалном карактеру интерфејса, лако га је имплементирати помоћу делегата или ламбде. Ово је посебно згодно за креирање Custom Views и ViewModel класа које треба да реагују на промене животног циклуса домаћина. Lifecycle објекат добијен из getLifecycle() пружа методе addObserver и removeObserver за управљање претплатама.
LifecycleOwner ради у спрези са два кључна класа: Lifecycle и LifecycleObserver. Lifecycle чува тренутно стање компоненте у облику enum State (INITIALIZED, CREATED, STARTED, RESUMED, DESTROYED) и прати прелазе између њих. Када се стање промени, Lifecycle обавештава све регистроване посматраче, позивајући одговарајуће анотиране методе. Овај механизам се назива „lifecycle-aware" — код се извршава само када се компонента налази у одговарајућем стању.
Механизам преноса догађаја се заснива на обрасцу Observer. LifecycleOwner игра улогу Observable, а имплементација LifecycleObserver — улогу Observer. Activity или Fragment при промени свог стања (onCreate → onStart → onResume → onPause → onStop → onDestroy) обавештава Lifecycle путем унутрашњег механизма ReportFragment, који се аутоматски додаје у AndroidX систем. Програмер не мора ручно да позива Lifecycle методе — све се одвија аутоматски.
| Lifecycle стање | Догађај | Метода животног циклуса Android-а |
|---|---|---|
| INITIALIZED | — | Пре 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 |
Важан детаљ: Lifecycle гарантује да ће догађаји ON_STOP и ON_DESTROY бити достављени чак и у случају ванредног завршетка процеса. То чини LifecycleOwner поузданим алатом за ослобађање критичних ресурса. За обично чување стања препоручује се коришћење SavedStateHandle у ViewModel-у, али LifecycleOwner обезбеђује основни ниво безбедности.
Постоје два начина да се претплатите на догађаје LifecycleOwner: класични LifecycleObserver са анотацијама и савремени DefaultLifecycleObserver са експлицитним методама. Други приступ препоручује Google од 2022. године, јер пружа бољу типску безбедност и избегава рефлексију која се користила у анотационом приступу. DefaultLifecycleObserver захтева Java 8+ или Kotlin и пожељан је за нове пројекте.
Пример претплате путем DefaultLifecycleObserver:
class MyObserver : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
// Покретање GPS праћења само када је компонента активна
startLocationUpdates()
}
override fun onStop(owner: LifecycleOwner) {
// Безбедно заустављање при преласку у позадински режим
stopLocationUpdates()
}
}
// Повезивање:
lifecycleOwner.lifecycle.addObserver(MyObserver())
Свака метода DefaultLifecycleObserver прима LifecycleOwner као параметар. Ово омогућава посматрачу да приступи контексту компоненте која се извршава без потребе да га прослеђује засебно. Овакав приступ чини код модуларнијим и тестибилнијим — Observer не зависи од конкретне имплементације Activity или Fragment, већ ради са апстракцијом LifecycleOwner.
Стари начин коришћења анотације @OnLifecycleEvent се још увек среће у наслеђеним пројектима, али његово коришћење се не препоручује за нови код. Рефлексија неопходна за обраду анотација додаје додатни overhead и може довести до грешака које се не откривају у фази компилације. Google званично саветује миграцију на DefaultLifecycleObserver.
// Застарели приступ — не препоручује се за нове пројекте
class MyLegacyObserver : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onStart() {
startLocationUpdates()
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onStop() {
stopLocationUpdates()
}
}
Анотациони приступ има значајан недостатак: недостатак контроле животног века Observer-а. Ако програмер заборави да одјави Observer при уништењу LifecycleOwner-а, Observer објекат остаје у меморији до покретања сакупљача смећа. DefaultLifecycleObserver решава овај проблем — Observer је везан за Lifecycle и аутоматски се одјављује при преласку у стање DESTROYED.
Почев од AppCompat 1.1.0 и AndroidX Fragment 1.2.0, све Activity и Fragment које наслеђују AppCompatActivity или Fragment аутоматски су LifecycleOwner. То значи да је метода getLifecycle() доступна у њима подразумевано, а претплата на догађаје животног циклуса ради без додатног подешавања. Програмеру је довољно да позове lifecycle.addObserver() из било ког места у Activity или Fragment.
Размотримо пример интеграције LifecycleOwner у Activity:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycle.addObserver(LocationObserver(this))
}
}
У овом примеру lifecycle је extension property, доступан захваљујући AndroidX Activity. LocationObserver ће аутоматски добијати обавештења о покретању (ON_START) и заустављању (ON_STOP) Activity. При ротацији екрана, Observer се обавештава о ON_DESTROY, а затим о ON_CREATE, што омогућава коректну обраду конфигурационих промена без додатног кода.
Fragment имплементира LifecycleOwner путем интерфејса, а његов Lifecycle је везан за животни циклус Fragment-а, а не родитељске Activity. Ово је важно: Lifecycle Fragment-а прелази у DESTROYED када се Fragment уклони из трансакције, док Activity може остати у RESUMED. Ова разлика омогућава Observer-у да се одвојено претплати на животни циклус сваке компоненте.
class MyFragment : Fragment() {
private val uiStateObserver = UiStateObserver()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
lifecycle.addObserver(uiStateObserver)
}
}
Важна предност коришћења LifecycleOwner у Fragment-у је аутоматско одјављивање при преласку Fragment-а у DESTROYED. Ово је посебно актуелно за ViewPager, где се Fragment-и могу динамички креирати и уништавати. Ручно управљање претплатама у овом сценарију било би изузетно сложено и подложно грешкама.
Интерфејс LifecycleOwner се може имплементирати у било којој класи која има животни циклус. Ово је корисно за Custom Views, Service, па чак и ViewModel у неким архитектонским решењима. Google пружа помоћну класу LifecycleRegistry која управља стањем Lifecycle-а и генерише догађаје. Програмер треба ручно да позива одговарајуће методе LifecycleRegistry при промени стања компоненте.
Пример имплементације LifecycleOwner у 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)
}
}
У овом примеру LifecycleRegistry игра улогу складишта стања. Методе onStart/onStop треба да позива родитељска компонента (нпр. Activity) када Custom View постаје видљив или се скрива. LifecycleRegistry аутоматски израчунава потребне догађаје за прелазак између стања и обавештава све пријављене Observer-е.
При имплементацији сопственог LifecycleOwner-а важно је поштовати правило: стање LifecycleRegistry-ја треба ажурирати последње у одговарајућој методи животног циклуса, након свих осталих операција. Ово гарантује да ће Observer-и добити обавештење када је компонента потпуно спремна за ново стање. Коришћење LifecycleRegistry.createUnsafe као алтернативе је такође могуће, али захтева опрез са нитима.
LifecycleOwner је темељ за неколико кључних Android Jetpack компоненти. LiveData користи LifecycleOwner за одређивање активног стања и аутоматско одјављивање при уништењу компоненте. ViewModel не имплементира LifecycleOwner директно, али може примати Lifecycle путем SavedStateHandle. Navigation Component користи LifecycleOwner за управљање претплатама у NavBackStackEntry. Разумевање ове повезаности помаже у изградњи архитектуре апликације на чврстом темељу.
Интеракција LiveData са 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)
// Код се извршава само када је Activity у стању RESUMED
updateUI(data)
}
}
}
LiveData захтева LifecycleOwner у методи observe() јер то гарантује да ће се ажурирања UI-ја дешавати само у активном стању. Ако је Activity у позадини, LiveData чува последњу вредност, али не обавештава Observer. При повратку у RESUMED, Observer добија актуелну вредност без додатних захтева ка мрежи или бази података.
DataBinding такође користи LifecycleOwner за повезивање observable поља са животним циклусом Activity или Fragment. Ово омогућава избегавање цурења меморије у комбинацији ViewModel + DataBinding — све претплате се аутоматски чисте при уништењу LifecycleOwner-а. Овакав приступ чини код декларативним и безбедним.
Правилно коришћење LifecycleOwner-а захтева поштовање неколико кључних правила. Прво и најважније: увек претплатите Observer у onCreate/onViewCreated, а не касније. Ово гарантује да ће Observer добити почетно стање Lifecycle-а (CREATED након onCreate) и неће пропустити догађаје. Друго правило: користите DefaultLifecycleObserver уместо анотационог приступа за све нове пројекте.
Савремени приступ раду са корутинама и LifecycleOwner — проширење repeatOnLifecycle:
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.flow.collect { value ->
updateUI(value)
}
}
}
Овај образац гарантује да је collect на Flow-у активан само у стању STARTED или RESUMED. При преласку у STOPPED, колекција се аутоматски отказује, а при повратку у STARTED — поново покреће. repeatOnLifecycle замењује ручно одјављивање од Flow-а у Fragment-у и препоручени је Google приступ за рад са асинхроним токовима података у UI компонентама.
Још једна важна препорука: не злоупотребљавајте LifecycleObserver за логику која није повезана са животним циклусом. Ако компонента треба да изврши радњу у одређеном стању, али не захтева одјаву при уништењу, боље је користити експлицитно позивање метода у onStart/onStop. LifecycleObserver је оправдан за дуготрајне компоненте (LocationListener, SensorManager), где је ручно управљање претплатама сложено и подложно грешкама.
Често постављана питања
LifecycleOwner — то је интерфејс који изјављује да објекат има животни циклус. Lifecycle — то је класа која чува тренутно стање и управља Observer-ом. LifecycleOwner пружа Lifecycle путем getLifecycle().
Не, Lifecycle аутоматски одјављује све Observer-е при преласку у DESTROYED. Ово је једна од главних предности LifecycleOwner-а — програмер не мора ручно да позива removeObserver у onDestroy.
Fragment имплементира LifecycleOwner путем интерфејса AndroidX фрагмената. Његов Lifecycle је везан за животни циклус Fragment-а одвојено од Activity. Ово омогућава Observer-у да реагује управо на догађаје Fragment-а, а не родитељске Activity.
Да, за то се користи LifecycleRegistry. Custom View мора да имплементира интерфејс LifecycleOwner и ручно ажурира стање LifecycleRegistry-ја при промени видљивости или причвршћивању за прозор.
LifecycleOwner решава други задатак: управљање претплатама на догађаје животног циклуса, а не отказивање корутина. За корутине се користи lifecycleScope, који аутоматски отказује покренуте корутине при уништењу LifecycleOwner-а.
Резиме
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође