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) and notifies all subscribed observers when it changes. LifecycleOwner is part of Architecture Components and is included in the lifecycle-runtime library.
The main purpose of the interface is to standardize access to the lifecycle. Before Jetpack, developers manually subscribed in onStart and unsubscribed in onStop, which led to code duplication and errors. LifecycleOwner solves this problem by providing a unified mechanism for all Android components. Instead of explicitly calling lifecycle methods, the developer subscribes to Lifecycle once, and notifications arrive automatically.
The interface is declared in Kotlin as a functional interface with a single abstract method:
interface LifecycleOwner {
val lifecycle: Lifecycle
}
Thanks to the functional nature of the interface, it is easy to implement using a delegate or lambda. This is especially convenient for creating Custom Views and ViewModel classes that need to respond to changes in the host's lifecycle. The Lifecycle object obtained from getLifecycle() provides addObserver and removeObserver methods for managing subscriptions.
LifecycleOwner works in conjunction with two key classes: Lifecycle and LifecycleObserver. Lifecycle stores the current state of the component as an enum State (INITIALIZED, CREATED, STARTED, RESUMED, DESTROYED) and tracks transitions between them. When the state changes, Lifecycle notifies all registered observers by calling the corresponding annotated methods. This mechanism is called “lifecycle-aware” — code is executed only when the component is in an appropriate state.
The event delivery mechanism is based on the Observer pattern. LifecycleOwner acts as the Observable, and the LifecycleObserver implementation acts as the Observer. When Activity or Fragment changes its state (onCreate → onStart → onResume → onPause → onStop → onDestroy), it notifies Lifecycle through the internal ReportFragment mechanism, which is automatically added to the AndroidX system. The developer does not need to manually call Lifecycle methods — everything happens automatically.
| Lifecycle State | Event | Android Lifecycle Method |
|---|---|---|
| INITIALIZED | — | Before 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 |
An important detail: Lifecycle guarantees that ON_STOP and ON_DESTROY events will be delivered even in case of a process crash. This makes LifecycleOwner a reliable tool for releasing critical resources. For regular state preservation, it is recommended to use SavedStateHandle in ViewModel, but LifecycleOwner provides a basic level of safety.
There are two ways to subscribe to LifecycleOwner events: the classic LifecycleObserver with annotations and the modern DefaultLifecycleObserver with explicit methods. Google has recommended the second approach since 2022, as it provides better type safety and avoids the reflection used in the annotation-based approach. DefaultLifecycleObserver requires Java 8+ or Kotlin and is the preferred choice for new projects.
Example of subscribing via DefaultLifecycleObserver:
class MyObserver : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
// Запуск GPS-трекінгу лише коли компонент активний
startLocationUpdates()
}
override fun onStop(owner: LifecycleOwner) {
// Безпечна зупинка при переході в фоновий режим
stopLocationUpdates()
}
}
// Підключення:
lifecycleOwner.lifecycle.addObserver(MyObserver())
Each method of DefaultLifecycleObserver takes a LifecycleOwner as a parameter. This allows the observer to access the context of the executing component without needing to pass it separately. This approach makes the code more modular and testable — the Observer does not depend on the specific implementation of Activity or Fragment but works with the LifecycleOwner abstraction.
The old approach using the @OnLifecycleEvent annotation is still found in legacy projects, but its use is not recommended for new code. The reflection required to process annotations adds overhead and can lead to errors that are not caught at compile time. Google officially advises migrating to DefaultLifecycleObserver.
// Застарілий підхід — не рекомендується для нових проектів
class MyLegacyObserver : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onStart() {
startLocationUpdates()
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onStop() {
stopLocationUpdates()
}
}
The annotation-based approach has a significant drawback: lack of Observer lifetime control. If the developer forgets to unsubscribe the Observer when the LifecycleOwner is destroyed, the Observer object remains in memory until the garbage collector runs. DefaultLifecycleObserver solves this problem — the Observer is bound to the Lifecycle and automatically unsubscribes upon transition to the DESTROYED state.
Since AppCompat 1.1.0 and AndroidX Fragment 1.2.0, all Activities and Fragments that extend AppCompatActivity or Fragment are automatically LifecycleOwners. This means that the getLifecycle() method is available by default, and subscribing to lifecycle events works without additional setup. The developer simply calls lifecycle.addObserver() from anywhere in the Activity or Fragment.
Let’s look at an example of integrating LifecycleOwner into an Activity:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycle.addObserver(LocationObserver(this))
}
}
In this example, lifecycle is an extension property available thanks to AndroidX Activity. The LocationObserver will automatically receive notifications about the start (ON_START) and stop (ON_STOP) of the Activity. When the screen is rotated, the Observer is notified of ON_DESTROY and then ON_CREATE, allowing configuration changes to be handled correctly without additional code.
Fragment implements LifecycleOwner through its interface, and its Lifecycle is tied to the Fragment’s lifecycle, not the parent Activity’s. This is important: the Fragment’s Lifecycle transitions to DESTROYED when the Fragment is removed from the transaction, while the Activity may remain in RESUMED. This distinction allows Observers to subscribe separately to the lifecycle of each component.
class MyFragment : Fragment() {
private val uiStateObserver = UiStateObserver()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
lifecycle.addObserver(uiStateObserver)
}
}
An important advantage of using LifecycleOwner in Fragment is automatic unsubscription when the Fragment transitions to DESTROYED. This is especially relevant for ViewPager, where Fragments can be created and destroyed dynamically. Manual subscription management in this scenario would be extremely complex and error-prone.
The LifecycleOwner interface can be implemented in any class that has a lifecycle. This is useful for Custom Views, Services, and even ViewModel in some architectural solutions. Google provides the helper class LifecycleRegistry, which manages the Lifecycle state and generates events. The developer needs to manually call the appropriate LifecycleRegistry methods when the component’s state changes.
Example of implementing LifecycleOwner in a 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)
}
}
In this example, LifecycleRegistry acts as the state store. The onStart/onStop methods should be called by the parent component (e.g., Activity) when the Custom View becomes visible or hidden. LifecycleRegistry automatically calculates the necessary events for transitioning between states and notifies all subscribed Observers.
When implementing a custom LifecycleOwner, it is important to follow the rule: the LifecycleRegistry state should be updated last in the corresponding lifecycle method, after all other operations. This ensures that Observers receive notification when the component is already fully ready for the new state. Using LifecycleRegistry.createUnsafe as an alternative is also possible but requires caution with threads.
LifecycleOwner is the foundation for several key Android Jetpack components. LiveData uses LifecycleOwner to determine the active state and automatically unsubscribe when the component is destroyed. ViewModel does not directly implement LifecycleOwner but can receive Lifecycle through SavedStateHandle. Navigation Component uses LifecycleOwner to manage subscriptions in NavBackStackEntry. Understanding this relationship helps build application architecture on a solid foundation.
LiveData interaction with 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 requires a LifecycleOwner in the observe() method because it guarantees that UI updates will only occur in the active state. If the Activity is in the background, LiveData keeps the latest value but does not notify the Observer. Upon returning to RESUMED, the Observer receives the current value without additional network or database requests.
DataBinding also uses LifecycleOwner to bind observable fields to the lifecycle of the Activity or Fragment. This helps avoid memory leaks in the ViewModel + DataBinding combination — all subscriptions are automatically cleared when the LifecycleOwner is destroyed. This approach makes the code declarative and safe.
Proper use of LifecycleOwner requires following several key rules. First and most important: always subscribe the Observer in onCreate/onViewCreated, not later. This ensures that the Observer receives the initial Lifecycle state (CREATED after onCreate) and does not miss events. The second rule: use DefaultLifecycleObserver instead of the annotation-based approach for all new projects.
The modern approach to working with coroutines and LifecycleOwner is the repeatOnLifecycle extension:
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.flow.collect { value ->
updateUI(value)
}
}
}
This pattern guarantees that collect on Flow is active only in the STARTED or RESUMED state. When transitioning to STOPPED, the collection is automatically cancelled, and upon returning to STARTED, it restarts. repeatOnLifecycle replaces manual unsubscription from Flow in Fragments and is Google’s recommended approach for working with asynchronous data streams in UI components.
Another important recommendation: do not overuse LifecycleObserver for logic unrelated to the lifecycle. If a component needs to perform an action at a specific state but does not require unsubscription upon destruction, it is better to use explicit method calls in onStart/onStop. LifecycleObserver is justified for long-lived components (LocationListener, SensorManager) where manual subscription management is complex and error-prone.
Часті запитання
LifecycleOwner is an interface that declares that an object has a lifecycle. Lifecycle is a class that stores the current state and manages Observers. LifecycleOwner provides Lifecycle via getLifecycle().
No, Lifecycle automatically unsubscribes all Observers upon transition to DESTROYED. This is one of the main advantages of LifecycleOwner — the developer does not need to manually call removeObserver in onDestroy.
Fragment implements LifecycleOwner through the AndroidX fragment interface. Its Lifecycle is tied to the Fragment’s lifecycle separately from the Activity. This allows the Observer to react specifically to Fragment events rather than the parent Activity’s.
Yes, LifecycleRegistry is used for this purpose. The Custom View must implement the LifecycleOwner interface and manually update the LifecycleRegistry state when visibility changes or when it is attached to a window.
LifecycleOwner solves a different problem: managing subscriptions to lifecycle events, not cancelling coroutines. For coroutines, lifecycleScope is used, which automatically cancels launched coroutines when the LifecycleOwner is destroyed.
Підсумок
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також