The Android Developer Challenge is back! Submit your idea before December 2.

androidx.lifecycle

Classes

AbstractSavedStateViewModelFactory

Skeleton of androidx.

AndroidViewModel

Application context aware ViewModel.

Lifecycle

Defines an object that has an Android Lifecycle.

LifecycleCoroutineScope

CoroutineScope tied to a Lifecycle and Dispatchers.Main.immediate

LifecycleRegistry

An implementation of Lifecycle that can handle multiple observers.

LifecycleService

A Service that is also a LifecycleOwner.

LiveData

LiveData is a data holder class that can be observed within a given lifecycle.

LiveDataReactiveStreams

Adapts LiveData input and output to the ReactiveStreams spec.

MediatorLiveData

LiveData subclass which may observe other LiveData objects and react on OnChanged events from them.

MutableLiveData

LiveData which publicly exposes setValue(T) and postValue(T) method.

ProcessLifecycleOwner

Class that provides lifecycle for the whole application process.

SavedStateHandle

A handle to saved state passed down to androidx.lifecycle.ViewModel.

SavedStateViewModelFactory

androidx.lifecycle.ViewModelProvider.Factory that can create ViewModels accessing and contributing to a saved state via SavedStateHandle received in a constructor.

ServiceLifecycleDispatcher

Helper class to dispatch lifecycle events for a service.

Transformations

Transformation methods for LiveData.

ViewModel

ViewModel is a class that is responsible for preparing and managing the data for an Activity or a Fragment.

ViewModelLazy

An implementation of Lazy used by androidx.fragment.app.Fragment.viewModels and androidx.activity.ComponentActivity.viewmodels.

ViewModelProvider

An utility class that provides ViewModels for a scope.

ViewModelProviders

Utilities methods for ViewModelStore class.

ViewModelStore

Class to store ViewModels.

ViewModelStores

Factory methods for ViewModelStore class.

Annotations

OnLifecycleEvent

Top-level functions summary

LiveData<T>
liveData(context: CoroutineContext = EmptyCoroutineContext, timeoutInMs: Long = DEFAULT_TIMEOUT, block: suspend LiveDataScope<T>.() -> Unit)

Builds a LiveData that has values yielded from the given block that executes on a LiveDataScope.

LiveData<T>
liveData(context: CoroutineContext = EmptyCoroutineContext, timeout: Duration, block: suspend LiveDataScope<T>.() -> Unit)

Builds a LiveData that has values yielded from the given block that executes on a LiveDataScope.

Extension functions summary

For kotlinx.coroutines.flow.Flow
LiveData<T>
Flow<T>.asLiveData(context: CoroutineContext = EmptyCoroutineContext, timeoutInMs: Long = DEFAULT_TIMEOUT)

Creates a LiveData that has values collected from the origin Flow.

LiveData<T>
Flow<T>.asLiveData(context: CoroutineContext = EmptyCoroutineContext, timeout: Duration)

Creates a LiveData that has values collected from the origin Flow.

For org.reactivestreams.Publisher
LiveData<T>
Publisher<T>.toLiveData()

Creates an observable LiveData stream from a ReactiveStreams Publisher.

For LiveData
Flow<T>

Creates a Flow containing values dispatched by originating LiveData: at the start a flow collector receives the latest value held by LiveData and then observes LiveData updates.

LiveData<X>

Creates a new LiveData object does not emit a value until the source this LiveData value has been changed.

LiveData<Y>
LiveData<X>.map(crossinline transform: (X) -> Y)

Returns a LiveData mapped from this LiveData by applying transform to each value set on this LiveData.

Observer<T>
LiveData<T>.observe(owner: LifecycleOwner, crossinline onChanged: (T) -> Unit)

Adds the given onChanged lambda as an observer within the lifespan of the given owner and returns a reference to observer.

LiveData<Y>
LiveData<X>.switchMap(crossinline transform: (X) -> LiveData<Y>)

Returns a LiveData mapped from the input this LiveData by applying transform to each value set on this.

Publisher<T>

Adapts the given LiveData stream to a ReactiveStreams Publisher.

For ViewModelProvider
VM

Returns an existing ViewModel or creates a new one in the scope (usually, a fragment or an activity), associated with this ViewModelProvider.

For LifecycleOwner
suspend T
LifecycleOwner.whenCreated(block: suspend CoroutineScope.() -> T)

Runs the given block when the LifecycleOwner's Lifecycle is at least in Lifecycle.State.CREATED state.

suspend T
LifecycleOwner.whenResumed(block: suspend CoroutineScope.() -> T)

Runs the given block when the LifecycleOwner's Lifecycle is at least in Lifecycle.State.RESUMED state.

suspend T
LifecycleOwner.whenStarted(block: suspend CoroutineScope.() -> T)

Runs the given block when the LifecycleOwner's Lifecycle is at least in Lifecycle.State.STARTED state.

For Lifecycle
suspend T
Lifecycle.whenCreated(block: suspend CoroutineScope.() -> T)

Runs the given block when the Lifecycle is at least in Lifecycle.State.CREATED state.

suspend T
Lifecycle.whenResumed(block: suspend CoroutineScope.() -> T)

Runs the given block when the Lifecycle is at least in Lifecycle.State.RESUMED state.

suspend T
Lifecycle.whenStarted(block: suspend CoroutineScope.() -> T)

Runs the given block when the Lifecycle is at least in Lifecycle.State.STARTED state.

suspend T
Lifecycle.whenStateAtLeast(minState: Lifecycle.State, block: suspend CoroutineScope.() -> 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.

Extension properties summary

Top-level functions

liveData

fun <T> liveData(context: CoroutineContext = EmptyCoroutineContext, timeoutInMs: Long = DEFAULT_TIMEOUT, block: suspend LiveDataScope<T>.() -> Unit): LiveData<T>

Builds a LiveData that has values yielded from the given block that executes on a LiveDataScope.

The block starts executing when the returned LiveData becomes active (LiveData.onActive). If the LiveData becomes inactive (LiveData.onInactive) while the block is executing, it will be cancelled after timeoutInMs milliseconds unless the LiveData becomes active again before that timeout (to gracefully handle cases like Activity rotation). Any value LiveDataScope.emited from a cancelled block will be ignored.

After a cancellation, if the LiveData becomes active again, the block will be re-executed from the beginning. If you would like to continue the operations based on where it was stopped last, you can use the LiveDataScope.latestValue function to get the last LiveDataScope.emited value.

If the block completes successfully or is cancelled due to reasons other than LiveData becoming inactive, it will not be re-executed even after LiveData goes through active inactive cycle.

As a best practice, it is important for the block to cooperate in cancellation. See kotlin coroutines documentation for details https://kotlinlang.org/docs/reference/coroutines/cancellation-and-timeouts.html.


// a simple LiveData that receives value 3, 3 seconds after being observed for the first time.
val data : LiveData<Int> = liveData {
    delay(3000)
    emit(3)
}


// a LiveData that fetches a `User` object based on a `userId` and refreshes it every 30 seconds
// as long as it is observed
val userId : LiveData<String> = ...
val user = userId.switchMap { id ->
    liveData {
      while(true) {
        // note that `while(true)` is fine because the `delay(30_000)` below will cooperate in
        // cancellation if LiveData is not actively observed anymore
        val data = api.fetch(id) // errors are ignored for brevity
        emit(data)
        delay(30_000)
      }
    }
}

// A retrying data fetcher with doubling back-off
val user = liveData {
    var backOffTime = 1_000
    var succeeded = false
    while(!succeeded) {
        try {
            emit(api.fetch(id))
            succeeded = true
        } catch(ioError : IOException) {
            delay(backOffTime)
            backOffTime *= minOf(backOffTime * 2, 60_000)
        }
    }
}

// a LiveData that tries to load the `User` from local cache first and then tries to fetch
// from the server and also yields the updated value
val user = liveData {
    // dispatch loading first
    emit(LOADING(id))
    // check local storage
    val cached = cache.loadUser(id)
    if (cached != null) {
        emit(cached)
    }
    if (cached == null || cached.isStale()) {
        val fresh = api.fetch(id) // errors are ignored for brevity
        cache.save(fresh)
        emit(fresh)
    }
}

// a LiveData that immediately receives a LiveData<User> from the database and yields it as a
// source but also tries to back-fill the database from the server
val user = liveData {
    val fromDb: LiveData<User> = roomDatabase.loadUser(id)
    emitSource(fromDb)
    val updated = api.fetch(id) // errors are ignored for brevity
    // Since we are using Room here, updating the database will update the `fromDb` LiveData
    // that was obtained above. See Room's documentation for more details.
    // https://developer.android.com/training/data-storage/room/accessing-data#query-observable
    roomDatabase.insert(updated)
}
Parameters
context The CoroutineContext to run the given block in. Defaults to EmptyCoroutineContext combined with Dispatchers.Main.immediate
timeoutInMs The timeout in ms before cancelling the block if there are no active observers (LiveData.hasActiveObservers. Defaults to DEFAULT_TIMEOUT.
block The block to run when the LiveData has active observers.

liveData

fun <T> liveData(context: CoroutineContext = EmptyCoroutineContext, timeout: Duration, block: suspend LiveDataScope<T>.() -> Unit): LiveData<T>

Builds a LiveData that has values yielded from the given block that executes on a LiveDataScope.

The block starts executing when the returned LiveData becomes active (LiveData.onActive). If the LiveData becomes inactive (LiveData.onInactive) while the block is executing, it will be cancelled after the timeout duration unless the LiveData becomes active again before that timeout (to gracefully handle cases like Activity rotation). Any value LiveDataScope.emited from a cancelled block will be ignored.

After a cancellation, if the LiveData becomes active again, the block will be re-executed from the beginning. If you would like to continue the operations based on where it was stopped last, you can use the LiveDataScope.latestValue function to get the last LiveDataScope.emited value.

If the block completes successfully or is cancelled due to reasons other than LiveData becoming inactive, it will not be re-executed even after LiveData goes through active inactive cycle.

As a best practice, it is important for the block to cooperate in cancellation. See kotlin coroutines documentation for details https://kotlinlang.org/docs/reference/coroutines/cancellation-and-timeouts.html.


// a simple LiveData that receives value 3, 3 seconds after being observed for the first time.
val data : LiveData<Int> = liveData {
    delay(3000)
    emit(3)
}


// a LiveData that fetches a `User` object based on a `userId` and refreshes it every 30 seconds
// as long as it is observed
val userId : LiveData<String> = ...
val user = userId.switchMap { id ->
    liveData {
      while(true) {
        // note that `while(true)` is fine because the `delay(30_000)` below will cooperate in
        // cancellation if LiveData is not actively observed anymore
        val data = api.fetch(id) // errors are ignored for brevity
        emit(data)
        delay(30_000)
      }
    }
}

// A retrying data fetcher with doubling back-off
val user = liveData {
    var backOffTime = 1_000
    var succeeded = false
    while(!succeeded) {
        try {
            emit(api.fetch(id))
            succeeded = true
        } catch(ioError : IOException) {
            delay(backOffTime)
            backOffTime *= minOf(backOffTime * 2, 60_000)
        }
    }
}

// a LiveData that tries to load the `User` from local cache first and then tries to fetch
// from the server and also yields the updated value
val user = liveData {
    // dispatch loading first
    emit(LOADING(id))
    // check local storage
    val cached = cache.loadUser(id)
    if (cached != null) {
        emit(cached)
    }
    if (cached == null || cached.isStale()) {
        val fresh = api.fetch(id) // errors are ignored for brevity
        cache.save(fresh)
        emit(fresh)
    }
}

// a LiveData that immediately receives a LiveData<User> from the database and yields it as a
// source but also tries to back-fill the database from the server
val user = liveData {
    val fromDb: LiveData<User> = roomDatabase.loadUser(id)
    emitSource(fromDb)
    val updated = api.fetch(id) // errors are ignored for brevity
    // Since we are using Room here, updating the database will update the `fromDb` LiveData
    // that was obtained above. See Room's documentation for more details.
    // https://developer.android.com/training/data-storage/room/accessing-data#query-observable
    roomDatabase.insert(updated)
}
Parameters
timeout The timeout duration before cancelling the block if there are no active observers (LiveData.hasActiveObservers.
block The block to run when the LiveData has active observers.

Extension functions

asFlow

fun <T> LiveData<T>.asFlow(): Flow<T>

Creates a Flow containing values dispatched by originating LiveData: at the start a flow collector receives the latest value held by LiveData and then observes LiveData updates.

When a collection of the returned flow starts the originating LiveData becomes active. Similarly, when a collection completes LiveData becomes inactive.

BackPressure: the returned flow is conflated. There is no mechanism to suspend an emission by LiveData due to a slow collector, so collector always gets the most recent value emitted.

asLiveData

@JvmOverloads fun <T> Flow<T>.asLiveData(context: CoroutineContext = EmptyCoroutineContext, timeoutInMs: Long = DEFAULT_TIMEOUT): LiveData<T>

Creates a LiveData that has values collected from the origin Flow.

The upstream flow collection starts when the returned LiveData becomes active (LiveData.onActive). If the LiveData becomes inactive (LiveData.onInactive) while the flow has not completed, the flow collection will be cancelled after timeoutInMs milliseconds unless the LiveData becomes active again before that timeout (to gracefully handle cases like Activity rotation).

After a cancellation, if the LiveData becomes active again, the upstream flow collection will be re-executed.

If the upstream flow completes successfully or is cancelled due to reasons other than LiveData becoming inactive, it will not be re-collected even after LiveData goes through active inactive cycle.

If flow completes with an exception, then exception will be delivered to the CoroutineExceptionHandler of provided context. By default EmptyCoroutineContext is used to so an exception will be delivered to main's thread UncaughtExceptionHandler. If your flow upstream is expected to throw, you can use catch operator on upstream flow to emit a helpful error object.

Parameters
context The CoroutineContext to collect the upstream flow in. Defaults to EmptyCoroutineContext combined with Dispatchers.Main.immediate
timeoutInMs The timeout in ms before cancelling the block if there are no active observers (LiveData.hasActiveObservers. Defaults to DEFAULT_TIMEOUT.

asLiveData

fun <T> Flow<T>.asLiveData(context: CoroutineContext = EmptyCoroutineContext, timeout: Duration): LiveData<T>

Creates a LiveData that has values collected from the origin Flow.

The upstream flow collection starts when the returned LiveData becomes active (LiveData.onActive). If the LiveData becomes inactive (LiveData.onInactive) while the flow has not completed, the flow collection will be cancelled after timeout unless the LiveData becomes active again before that timeout (to gracefully handle cases like Activity rotation).

After a cancellation, if the LiveData becomes active again, the upstream flow collection will be re-executed.

If the upstream flow completes successfully or is cancelled due to reasons other than LiveData becoming inactive, it will not be re-collected even after LiveData goes through active inactive cycle.

If flow completes with an exception, then exception will be delivered to the CoroutineExceptionHandler of provided context. By default EmptyCoroutineContext is used to so an exception will be delivered to main's thread UncaughtExceptionHandler. If your flow upstream is expected to throw, you can use catch operator on upstream flow to emit a helpful error object.

Parameters
context The CoroutineContext to collect the upstream flow in. Defaults to EmptyCoroutineContext combined with Dispatchers.Main.immediate
timeout The timeout in ms before cancelling the block if there are no active observers (LiveData.hasActiveObservers. Defaults to DEFAULT_TIMEOUT.

distinctUntilChanged

inline fun <X> LiveData<X>.distinctUntilChanged(): LiveData<X>

Creates a new LiveData object does not emit a value until the source this LiveData value has been changed. The value is considered changed if equals() yields false.

get

@MainThread inline fun <reified VM : ViewModel> ViewModelProvider.get(): VM

Returns an existing ViewModel or creates a new one in the scope (usually, a fragment or an activity), associated with this ViewModelProvider.

map

inline fun <X, Y> LiveData<X>.map(crossinline transform: (X) -> Y): LiveData<Y>

Returns a LiveData mapped from this LiveData by applying transform to each value set on this LiveData.

This method is analogous to io.reactivex.Observable.map.

transform will be executed on the main thread.

Here is an example mapping a simple User struct in a LiveData to a LiveData containing their full name as a String.


val userLD : LiveData<User> = ...;
val userFullNameLD: LiveData<String> = userLD.map { user -> user.firstName + user.lastName }

observe

@MainThread inline fun <T> LiveData<T>.observe(owner: LifecycleOwner, crossinline onChanged: (T) -> Unit): Observer<T>

Adds the given onChanged lambda as an observer within the lifespan of the given owner and returns a reference to observer. The events are dispatched on the main thread. If LiveData already has data set, it will be delivered to the onChanged.

The observer will only receive events if the owner is in Lifecycle.State.STARTED or Lifecycle.State.RESUMED state (active).

If the owner moves to the Lifecycle.State.DESTROYED state, the observer will automatically be removed.

When data changes while the owner is not active, it will not receive any updates. If it becomes active again, it will receive the last available data automatically.

LiveData keeps a strong reference to the observer and the owner as long as the given LifecycleOwner is not destroyed. When it is destroyed, LiveData removes references to the observer and the owner.

If the given owner is already in Lifecycle.State.DESTROYED state, LiveData ignores the call.

switchMap

inline fun <X, Y> LiveData<X>.switchMap(crossinline transform: (X) -> LiveData<Y>): LiveData<Y>

Returns a LiveData mapped from the input this LiveData by applying transform to each value set on this.

Note that when the backing LiveData is switched, no further values from the older LiveData will be set to the output LiveData. In this way, the method is analogous to io.reactivex.Observable.switchMap.

transform will be executed on the main thread.

Here is an example class that holds a typed-in name of a user String (such as from an EditText) in a MutableLiveData and returns a LiveData containing a List of User objects for users that have that name. It populates that LiveData by requerying a repository-pattern object each time the typed name changes.


class UserViewModel: AndroidViewModel {
    val nameQueryLiveData : MutableLiveData<String> = ...

    fun usersWithNameLiveData(): LiveData<List<String>> = nameQueryLiveData.switchMap {
        name -> myDataSource.usersWithNameLiveData(name)
    }

    fun setNameQuery(val name: String) {
        this.nameQueryLiveData.value = name;
    }
}

toLiveData

inline fun <T> Publisher<T>.toLiveData(): LiveData<T>

Creates an observable LiveData stream from a ReactiveStreams Publisher.

toPublisher

inline fun <T> LiveData<T>.toPublisher(lifecycle: LifecycleOwner): Publisher<T>

Adapts the given LiveData stream to a ReactiveStreams Publisher.

whenCreated

suspend fun <T> LifecycleOwner.whenCreated(block: suspend CoroutineScope.() -> T): T

Runs the given block when the LifecycleOwner's Lifecycle is at least in Lifecycle.State.CREATED state.

whenCreated

suspend fun <T> Lifecycle.whenCreated(block: suspend CoroutineScope.() -> T): T

Runs the given block when the Lifecycle is at least in Lifecycle.State.CREATED state.

whenResumed

suspend fun <T> LifecycleOwner.whenResumed(block: suspend CoroutineScope.() -> T): T

Runs the given block when the LifecycleOwner's Lifecycle is at least in Lifecycle.State.RESUMED state.

whenResumed

suspend fun <T> Lifecycle.whenResumed(block: suspend CoroutineScope.() -> T): T

Runs the given block when the Lifecycle is at least in Lifecycle.State.RESUMED state.

whenStarted

suspend fun <T> LifecycleOwner.whenStarted(block: suspend CoroutineScope.() -> T): T

Runs the given block when the LifecycleOwner's Lifecycle is at least in Lifecycle.State.STARTED state.

whenStarted

suspend fun <T> Lifecycle.whenStarted(block: suspend CoroutineScope.() -> T): T

Runs the given block when the Lifecycle is at least in Lifecycle.State.STARTED state.

whenStateAtLeast

suspend fun <T> 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 The desired minimum state to run the block.
block The block to run when the lifecycle is at least in minState.
Return

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

lifecycleScope

val LifecycleOwner.lifecycleScope: LifecycleCoroutineScope

CoroutineScope tied to this LifecycleOwner's Lifecycle.

This scope will be cancelled when the Lifecycle is destroyed.

This scope is bound to Dispatchers.Main.immediate.

viewModelScope

val ViewModel.viewModelScope: CoroutineScope

CoroutineScope tied to this ViewModel. This scope will be canceled when ViewModel will be cleared, i.e ViewModel.onCleared is called

This scope is bound to Dispatchers.Main.immediate