Lifecycle
-
Cmn
abstract class Lifecycle
LifecycleRegistry |
An implementation of |
Defines an object that has an Android Lifecycle. androidx.fragment.app.Fragment and androidx.fragment.app.FragmentActivity classes implement LifecycleOwner interface which has the LifecycleOwner.getLifecycle method to access the Lifecycle. You can also implement LifecycleOwner in your own classes.
Event.ON_CREATE, Event.ON_START, Event.ON_RESUME events in this class are dispatched after the LifecycleOwner's related method returns. Event.ON_PAUSE, Event.ON_STOP, Event.ON_DESTROY events in this class are dispatched before the LifecycleOwner's related method is called. For instance, Event.ON_START will be dispatched after android.app.Activity.onStart returns, Event.ON_STOP will be dispatched before android.app.Activity.onStop is called. This gives you certain guarantees on which state the owner is in.
To observe lifecycle events call .addObserver passing an object that implements either DefaultLifecycleObserver or LifecycleEventObserver.
Summary
Nested types |
|---|
enum Lifecycle.Event : Enum |
enum Lifecycle.State : EnumLifecycle states. |
Public constructors |
|
|---|---|
|
Cmn
|
Public functions |
||
|---|---|---|
abstract Unit |
@MainThreadAdds a LifecycleObserver that will be notified when the LifecycleOwner changes state. |
Cmn
|
abstract Unit |
@MainThreadRemoves the given observer from the observers list. |
Cmn
|
Public properties |
||
|---|---|---|
abstract Lifecycle.State |
Returns the current state of the Lifecycle. |
Cmn
|
open StateFlow<Lifecycle.State> |
Returns a |
Cmn
|
Extension functions |
||
|---|---|---|
State<Lifecycle.State> |
Collects values from the |
Cmn
|
suspend T |
<T : Any?> Lifecycle.This function is deprecated. whenCreated has been deprecated because it runs the block on a pausing dispatcher that suspends, rather than cancels work when the lifecycle state goes below the given state. |
android
|
suspend T |
<T : Any?> Lifecycle.This function is deprecated. whenResumed has been deprecated because it runs the block on a pausing dispatcher that suspends, rather than cancels work when the lifecycle state goes below the given state. |
android
|
suspend T |
<T : Any?> Lifecycle.This function is deprecated. whenStarted has been deprecated because it runs the block on a pausing dispatcher that suspends, rather than cancels work when the lifecycle state goes below the given state. |
android
|
suspend T |
<T : Any?> Lifecycle.This function is deprecated. whenStateAtLeast has been deprecated because it runs the block on a pausing dispatcher that suspends, rather than cancels work when the lifecycle state goes below the given state. |
android
|
suspend Unit |
Lifecycle.repeatOnLifecycle(Runs the given |
Cmn
|
suspend inline R |
<R : Any?> Lifecycle.withCreated(crossinline block: () -> R)Run |
Cmn
|
suspend inline R |
<R : Any?> Lifecycle.withResumed(crossinline block: () -> R)Run |
Cmn
|
suspend inline R |
<R : Any?> Lifecycle.withStarted(crossinline block: () -> R)Run |
Cmn
|
suspend inline R |
<R : Any?> Lifecycle.withStateAtLeast(Run |
Cmn
|
Extension properties |
||
|---|---|---|
LifecycleCoroutineScope |
|
Cmn
|
Flow<Lifecycle.Event> |
Creates a |
Cmn
|
Public constructors
Public functions
addObserver
@MainThread
abstract fun addObserver(observer: LifecycleObserver): Unit
Adds a LifecycleObserver that will be notified when the LifecycleOwner changes state.
The given observer will be brought to the current state of the LifecycleOwner. For example, if the LifecycleOwner is in State.STARTED state, the given observer will receive Event.ON_CREATE, Event.ON_START events.
| Parameters | |
|---|---|
observer: LifecycleObserver |
The observer to notify. |
removeObserver
@MainThread
abstract fun removeObserver(observer: LifecycleObserver): Unit
Removes the given observer from the observers list.
If this method is called while a state change is being dispatched,
-
If the given observer has not yet received that event, it will not receive it.
-
If the given observer has more than 1 method that observes the currently dispatched event and at least one of them received the event, all of them will receive the event and the removal will happen afterwards.
| Parameters | |
|---|---|
observer: LifecycleObserver |
The observer to be removed. |
Public properties
currentState
abstract val currentState: Lifecycle.State
Returns the current state of the Lifecycle.
| Returns | |
|---|---|
Lifecycle.State |
The current state of the Lifecycle. |
currentStateFlow
open val currentStateFlow: StateFlow<Lifecycle.State>
Returns a StateFlow where the StateFlow.value represents the current State of this Lifecycle.
| Returns | |
|---|---|
StateFlow<Lifecycle.State> |
|
Extension functions
currentStateAsState
@Composable
fun Lifecycle.currentStateAsState(): State<Lifecycle.State>
Collects values from the Lifecycle.currentStateFlow and represents its latest value via State. The StateFlow.value is used as an initial value. Every time there would be new value posted into the StateFlow the returned State will be updated causing recomposition of every State.value usage.
whenCreated
suspend fun <T : Any?> Lifecycle.whenCreated(block: suspend CoroutineScope.() -> T): T
Runs the given block when the Lifecycle is at least in Lifecycle.State.CREATED state.
| See also | |
|---|---|
whenStateAtLeast |
for details |
whenResumed
suspend fun <T : Any?> Lifecycle.whenResumed(block: suspend CoroutineScope.() -> T): T
Runs the given block when the Lifecycle is at least in Lifecycle.State.RESUMED state.
| See also | |
|---|---|
whenStateAtLeast |
for details |
whenStarted
suspend fun <T : Any?> Lifecycle.whenStarted(block: suspend CoroutineScope.() -> T): T
Runs the given block when the Lifecycle is at least in Lifecycle.State.STARTED state.
| See also | |
|---|---|
whenStateAtLeast |
for details |
whenStateAtLeast
suspend fun <T : Any?> Lifecycle.whenStateAtLeast(
minState: Lifecycle.State,
block: suspend CoroutineScope.() -> T
): T
Runs the given block on a CoroutineDispatcher that executes the block on the main thread and suspends the execution unless the Lifecycle's state is at least minState.
If the Lifecycle moves to a lesser state while the block is running, the block will be suspended until the Lifecycle reaches to a state greater or equal to minState.
Note that this won't effect any sub coroutine if they use a different CoroutineDispatcher. However, the block will not resume execution when the sub coroutine finishes unless the Lifecycle is at least in minState.
If the Lifecycle is destroyed while the block is suspended, the block will be cancelled which will also cancel any child coroutine launched inside the block.
If you have a try finally block in your code, the finally might run after the Lifecycle moves outside the desired state. It is recommended to check the Lifecycle.getCurrentState before accessing the UI. Similarly, if you have a catch statement that might catch CancellationException, you should check the Lifecycle.getCurrentState before accessing the UI. See the sample below for more details.
// running a block of code only if lifecycle is STARTED
viewLifecycle.whenStateAtLeast(Lifecycle.State.STARTED) {
// here, we are on the main thread and view lifecycle is guaranteed to be STARTED or RESUMED.
// We can safely access our views.
loadingBar.visibility = View.VISIBLE
try {
// we can call any suspend function
val data = withContext(Dispatchers.IO) {
// this will run in IO thread pool. It will keep running as long as Lifecycle
// is not DESTROYED. If it is destroyed, this coroutine will be cancelled as well.
// However, we CANNOT access Views here.
// We are using withContext(Dispatchers.IO) here just for demonstration purposes.
// Such code should live in your business logic classes and your UI should use a
// ViewModel (or similar) to access it.
api.getUser()
}
// this line will execute on the main thread and only if the lifecycle is in at least
// STARTED state (STARTED is the parameter we've passed to whenStateAtLeast)
// Because of this guarantee, we can safely access the UI again.
loadingBar.visibility = View.GONE
nameTextView.text = user.name
lastNameTextView.text = user.lastName
} catch(ex : UserNotFoundException) {
// same as above, this code can safely access UI elements because it only runs if
// view lifecycle is at least STARTED
loadingBar.visibility = View.GONE
showErrorDialog(ex)
} catch(th : Throwable) {
// Unlike the catch statement above, this catch statements it too generic and might
// also catch the CancellationException. Before accessing UI, you should check isActive
// or lifecycle state
if (viewLifecycle.currentState >= Lifecycle.State.STARTED) {
// here you can access the view because you've checked the coroutine is active
}
} finally {
// in case of cancellation, this line might run even if the Lifecycle is not DESTROYED.
// You cannot access Views here unless you check `isActive` or lifecycle state
if (viewLifecycle.currentState >= Lifecycle.State.STARTED) {
// safe to access views
} else {
// not safe to access views
}
}
}| Parameters | |
|---|---|
minState: Lifecycle.State |
The desired minimum state to run the |
block: suspend CoroutineScope.() -> T |
The block to run when the lifecycle is at least in |
| Returns | |
|---|---|
T |
repeatOnLifecycle
suspend fun Lifecycle.repeatOnLifecycle(
state: Lifecycle.State,
block: suspend CoroutineScope.() -> Unit
): Unit
Runs the given block in a new coroutine when this Lifecycle is at least at state and suspends the execution until this Lifecycle is Lifecycle.State.DESTROYED.
The block will cancel and re-launch as the lifecycle moves in and out of the target state.
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
/* ... */
// Runs the block of code in a coroutine when the lifecycle is at least STARTED.
// The coroutine will be cancelled when the ON_STOP event happens and will
// restart executing if the lifecycle receives the ON_START event again.
lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
uiStateFlow.collect { uiState ->
updateUi(uiState)
}
}
}
}
}
The best practice is to call this function when the lifecycle is initialized. For example, onCreate in an Activity, or onViewCreated in a Fragment. Otherwise, multiple repeating coroutines doing the same could be created and be executed at the same time.
Repeated invocations of block will run serially, that is they will always wait for the previous invocation to fully finish before re-starting execution as the state moves in and out of the required state.
Warning: Lifecycle.State.INITIALIZED is not allowed in this API. Passing it as a parameter will throw an IllegalArgumentException.
| Parameters | |
|---|---|
state: Lifecycle.State |
|
block: suspend CoroutineScope.() -> Unit |
The block to run when the lifecycle is at least in |
withCreated
suspend inline fun <R : Any?> Lifecycle.withCreated(crossinline block: () -> R): R
Run block with this Lifecycle in a Lifecycle.State of at least Lifecycle.State.CREATED and resume with the result. Throws the CancellationException if the lifecycle has reached Lifecycle.State.DESTROYED by the time of the call or before block is able to run.
withResumed
suspend inline fun <R : Any?> Lifecycle.withResumed(crossinline block: () -> R): R
Run block with this Lifecycle in a Lifecycle.State of at least Lifecycle.State.RESUMED and resume with the result. Throws the CancellationException if the lifecycle has reached Lifecycle.State.DESTROYED by the time of the call or before block is able to run.
withStarted
suspend inline fun <R : Any?> Lifecycle.withStarted(crossinline block: () -> R): R
Run block with this Lifecycle in a Lifecycle.State of at least Lifecycle.State.STARTED and resume with the result. Throws the CancellationException if the lifecycle has reached Lifecycle.State.DESTROYED by the time of the call or before block is able to run.
withStateAtLeast
suspend inline fun <R : Any?> Lifecycle.withStateAtLeast(
state: Lifecycle.State,
crossinline block: () -> R
): R
Run block with this Lifecycle in a Lifecycle.State of at least state and resume with the result. Throws the CancellationException if the lifecycle has reached Lifecycle.State.DESTROYED by the time of the call or before block is able to run.
Extension properties
coroutineScope
val Lifecycle.coroutineScope: LifecycleCoroutineScope
CoroutineScope tied to this Lifecycle.
This scope will be cancelled when the Lifecycle is destroyed.
This scope is bound to Dispatchers.Main.immediate
eventFlow
val Lifecycle.eventFlow: Flow<Lifecycle.Event>
Creates a Flow of Lifecycle.Events containing values dispatched by this Lifecycle.