androidx.lifecycle.viewmodel.compose

Objects

LocalViewModelStoreOwner

The CompositionLocal containing the current ViewModelStoreOwner.

Cmn

Annotations

Top-level functions summary

ViewModelStoreOwner
@Composable
rememberViewModelStoreOwner(
    provider: ViewModelStoreProvider,
    key: Any?,
    savedStateRegistryOwner: SavedStateRegistryOwner?
)

Remembers a ViewModelStoreOwner scoped to the current composable using an existing provider.

Cmn
ViewModelStoreOwner
@Composable
rememberViewModelStoreOwner(
    parent: ViewModelStoreOwner?,
    savedStateRegistryOwner: SavedStateRegistryOwner?,
    defaultCreationExtras: CreationExtras,
    defaultFactory: ViewModelProvider.Factory
)

Remembers a ViewModelStoreOwner scoped to the current composable.

Cmn
ViewModelStoreProvider
@Composable
rememberViewModelStoreProvider(
    parent: ViewModelStoreOwner?,
    defaultCreationExtras: CreationExtras,
    defaultFactory: ViewModelProvider.Factory
)

Remembers a new ViewModelStoreProvider which creates a ViewModel scope linked to a parent owner found in the composition.

Cmn
inline VM
@Composable
<VM : ViewModel> viewModel(
    viewModelStoreOwner: ViewModelStoreOwner,
    key: String?,
    noinline initializer: CreationExtras.() -> VM
)

Returns an existing ViewModel or creates a new one in the scope (usually, a fragment or an activity)

Cmn
inline VM
@Composable
<VM : ViewModel> viewModel(
    viewModelStoreOwner: ViewModelStoreOwner,
    key: String?,
    factory: ViewModelProvider.Factory?,
    extras: CreationExtras
)

Returns an existing ViewModel or creates a new one in the given owner (usually, a fragment or an activity), defaulting to the owner provided by LocalViewModelStoreOwner.

Cmn
VM
@Composable
<VM : ViewModel> viewModel(
    modelClass: Class<VM>,
    viewModelStoreOwner: ViewModelStoreOwner,
    key: String?,
    factory: ViewModelProvider.Factory?,
    extras: CreationExtras
)

Returns an existing ViewModel or creates a new one in the scope (usually, a fragment or an activity)

android
VM
@Composable
<VM : ViewModel> viewModel(
    modelClass: KClass<VM>,
    viewModelStoreOwner: ViewModelStoreOwner,
    key: String?,
    factory: ViewModelProvider.Factory?,
    extras: CreationExtras
)

Returns an existing ViewModel or creates a new one in the scope (usually, a fragment or an activity)

Cmn

Extension functions summary

PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, T>>
@SavedStateHandleSaveableApi
<T : Any> SavedStateHandle.saveable(saver: Saver<T, Any>, init: () -> T)

Inter-opt between SavedStateHandle and Saver so that any state holder that is being saved via androidx.compose.runtime.saveable.rememberSaveable with a custom Saver can also be saved with SavedStateHandle.

Cmn
PropertyDelegateProvider<Any?, ReadWriteProperty<Any?, T>>
@SavedStateHandleSaveableApi
<T : Any?, M : MutableState<T>> SavedStateHandle.saveable(
    stateSaver: Saver<T, Any>,
    init: () -> M
)

Inter-opt between SavedStateHandle and Saver so that any state holder that is being saved via androidx.compose.runtime.saveable.rememberSaveable with a custom Saver can also be saved with SavedStateHandle.

Cmn
T
@SavedStateHandleSaveableApi
<T : Any> SavedStateHandle.saveable(
    key: String,
    saver: Saver<T, Any>,
    init: () -> T
)

Inter-opt between SavedStateHandle and Saver so that any state holder that is being saved via androidx.compose.runtime.saveable.rememberSaveable with a custom Saver can also be saved with SavedStateHandle.

Cmn
MutableState<T>
@SavedStateHandleSaveableApi
<T : Any?> SavedStateHandle.saveable(
    key: String,
    stateSaver: Saver<T, Any>,
    init: () -> MutableState<T>
)

Inter-opt between SavedStateHandle and Saver so that any state holder that is being saved via androidx.compose.runtime.saveable.rememberSaveable with a custom Saver can also be saved with SavedStateHandle.

Cmn

Top-level properties summary

HostDefaultKey<ViewModelStoreOwner?>

A HostDefaultKey used to retrieve the ViewModelStoreOwner provided by the current hosting environment.

Cmn
android
N

Top-level functions

rememberViewModelStoreOwner

@Composable
fun rememberViewModelStoreOwner(
    provider: ViewModelStoreProvider,
    key: Any? = currentCompositeKeyHashCode,
    savedStateRegistryOwner: SavedStateRegistryOwner? = LocalSavedStateRegistryOwner.current
): ViewModelStoreOwner

Remembers a ViewModelStoreOwner scoped to the current composable using an existing provider.

This function creates an owner unique to this specific call site in the composition hierarchy. While this composable is active, it maintains an active reference to the underlying ViewModelStore, preventing it from being cleared.

Note: Unlike many other scoped owners, ViewModels created with this owner are not automatically cleared simply because this composable leaves the composition. The ViewModelStore is only cleared when ViewModelStoreProvider.clearKey is explicitly called for this key.

This function is responsible for releasing its reference to the store when it leaves the composition, allowing the provider to perform cleanup if the store has been marked for clearing.

Parameters
provider: ViewModelStoreProvider

The ViewModelStoreProvider that manages the creation and cleanup of the underlying ViewModelStore.

key: Any? = currentCompositeKeyHashCode

A unique identifier for this call site to isolate its store from others. Defaults to currentCompositeKeyHashCode. If called multiple times in the same scope or loop, provide a custom key to ensure each instance gets its own ViewModelStore.

savedStateRegistryOwner: SavedStateRegistryOwner? = LocalSavedStateRegistryOwner.current

An optional SavedStateRegistryOwner to delegate saved state operations. When null, ViewModels created in this scope do not support saved state.

Returns
ViewModelStoreOwner

A ViewModelStoreOwner remembered across compositions and scoped to this call site.

rememberViewModelStoreOwner

@Composable
fun rememberViewModelStoreOwner(
    parent: ViewModelStoreOwner? = checkNotNull(LocalViewModelStoreOwner.current) { "CompositionLocal LocalViewModelStoreOwner not present" },
    savedStateRegistryOwner: SavedStateRegistryOwner? = LocalSavedStateRegistryOwner.current,
    defaultCreationExtras: CreationExtras = parent.defaultViewModelCreationExtras,
    defaultFactory: ViewModelProvider.Factory = parent.defaultViewModelProviderFactory
): ViewModelStoreOwner

Remembers a ViewModelStoreOwner scoped to the current composable.

This function creates an owner that is unique to this specific call site in the composition hierarchy. It allows creating ViewModels that are strictly scoped to this composable's lifecycle: they are created when this composable enters the composition and cleared immediately when it leaves.

The owner is linked to the parent, ensuring that configuration changes (like rotation) are handled correctly: the ViewModels survive rotation if the parent does, but are destroyed if the parent is destroyed.

Null parent: If parent is EXPLICITLY null, this creates a root provider that runs independently. By default, it requires a parent from the LocalViewModelStoreOwner and will throw an IllegalStateException if one is not present.

Parameters
parent: ViewModelStoreOwner? = checkNotNull(LocalViewModelStoreOwner.current) { "CompositionLocal LocalViewModelStoreOwner not present" }

The ViewModelStoreOwner to use as the parent. Defaults to the owner from LocalViewModelStoreOwner.

savedStateRegistryOwner: SavedStateRegistryOwner? = LocalSavedStateRegistryOwner.current

An optional SavedStateRegistryOwner to delegate saved state operations. When null, ViewModels created in this scope do not support saved state.

defaultCreationExtras: CreationExtras = parent.defaultViewModelCreationExtras

The CreationExtras to use. Defaults to the parent's default extras.

defaultFactory: ViewModelProvider.Factory = parent.defaultViewModelProviderFactory

The ViewModelProvider.Factory to use for creating ViewModels in this scope. Defaults to the parent's default factory.

Returns
ViewModelStoreOwner

A ViewModelStoreOwner that is remembered across compositions and scoped to this call site.

rememberViewModelStoreProvider

@Composable
fun rememberViewModelStoreProvider(
    parent: ViewModelStoreOwner? = checkNotNull(LocalViewModelStoreOwner.current) { "CompositionLocal LocalViewModelStoreOwner not present" },
    defaultCreationExtras: CreationExtras = parent.defaultViewModelCreationExtras,
    defaultFactory: ViewModelProvider.Factory = parent.defaultViewModelProviderFactory
): ViewModelStoreProvider

Remembers a new ViewModelStoreProvider which creates a ViewModel scope linked to a parent owner found in the composition.

This composable creates a provider that links to any parent owner found in the composition, forming a parent-child relationship. If no parent exists, it automatically becomes a new root provider. This is useful for isolating ViewModel instances within specific UI sections, such as a self-contained feature screen, dialog, or tab, ensuring they are cleared when that section is removed.

The provider's lifecycle is automatically managed. It is created only once and automatically disposed of when the composable leaves the composition. Crucially, it is aware of the parent's state and will survive configuration changes (like device rotation) if the parent does.

Null parent: If parent is EXPLICITLY null, this creates a root provider that runs independently. By default, it requires a parent from the LocalViewModelStoreOwner and will throw an IllegalStateException if one is not present.

Parameters
parent: ViewModelStoreOwner? = checkNotNull(LocalViewModelStoreOwner.current) { "CompositionLocal LocalViewModelStoreOwner not present" }

The ViewModelStoreOwner to use as the parent, or null if it is a root. Defaults to the owner from LocalViewModelStoreOwner.

defaultCreationExtras: CreationExtras = parent.defaultViewModelCreationExtras

The CreationExtras to use. Defaults to the parent's default extras.

defaultFactory: ViewModelProvider.Factory = parent.defaultViewModelProviderFactory

The ViewModelProvider.Factory to use for creating ViewModels in this scope. Defaults to the parent's default factory.

Returns
ViewModelStoreProvider

A new ViewModelStoreProvider that is remembered across compositions.

@Composable
inline fun <VM : ViewModel> viewModel(
    viewModelStoreOwner: ViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) { "No ViewModelStoreOwner was provided via LocalViewModelStoreOwner" },
    key: String? = null,
    noinline initializer: CreationExtras.() -> VM
): VM

Returns an existing ViewModel or creates a new one in the scope (usually, a fragment or an activity)

The created ViewModel is associated with the given viewModelStoreOwner and will be retained as long as the scope is alive (e.g. if it is an activity, until it is finished or process is killed).

If the viewModelStoreOwner implements HasDefaultViewModelProviderFactory its default CreationExtras are the ones that will be provided to the receiver scope from the initializer

import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.createSavedStateHandle
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
import androidx.lifecycle.viewmodel.compose.viewModel

// Just like any call to viewModel(), the default owner is the LocalViewModelStoreOwner.current.
// The lambda is only called the first time the ViewModel needs to be created.
val viewModel = viewModel {
    // Within the lambda, you have direct access to the CreationExtras which allows you to call
    // extension methods on CreationExtras such as createSavedStateHandle()
    val handle = createSavedStateHandle()
    // You can send any custom parameter, repository, etc. to your ViewModel.
    SavedStateViewModel(handle, "custom_value")
}
// The handle and parameter are now available from the ViewModel
viewModel.handle
viewModel.value
Parameters
viewModelStoreOwner: ViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) { "No ViewModelStoreOwner was provided via LocalViewModelStoreOwner" }

The scope that the created ViewModel should be associated with.

key: String? = null

The key to use to identify the ViewModel.

noinline initializer: CreationExtras.() -> VM

lambda used to create an instance of the ViewModel class

Returns
VM

A ViewModel that is an instance of the given VM type.

@Composable
inline fun <VM : ViewModel> viewModel(
    viewModelStoreOwner: ViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) { "No ViewModelStoreOwner was provided via LocalViewModelStoreOwner" },
    key: String? = null,
    factory: ViewModelProvider.Factory? = null,
    extras: CreationExtras = viewModelStoreOwner.defaultViewModelCreationExtras
): VM

Returns an existing ViewModel or creates a new one in the given owner (usually, a fragment or an activity), defaulting to the owner provided by LocalViewModelStoreOwner.

The created ViewModel is associated with the given viewModelStoreOwner and will be retained as long as the owner is alive (e.g. if it is an activity, until it is finished or process is killed).

If default arguments are provided via the CreationExtras, they will be available to the appropriate factory when the ViewModel is created.

import androidx.compose.runtime.remember
import androidx.core.os.bundleOf
import androidx.lifecycle.DEFAULT_ARGS_KEY
import androidx.lifecycle.HasDefaultViewModelProviderFactory
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.MutableCreationExtras
import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
import androidx.lifecycle.viewmodel.compose.viewModel

val owner = LocalViewModelStoreOwner.current
val defaultExtras =
    (owner as? HasDefaultViewModelProviderFactory)?.defaultViewModelCreationExtras
        ?: CreationExtras.Empty
// Custom extras should always be added on top of the default extras
val extras = MutableCreationExtras(defaultExtras)
extras[DEFAULT_ARGS_KEY] =
    @Suppress("DEPRECATION") // bundleOf is deprecated
    bundleOf("test" to "my_value")
// This factory is normally created separately and passed in
val customFactory = remember {
    object : ViewModelProvider.Factory {
        override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T {
            val args = extras[DEFAULT_ARGS_KEY]?.getString("test")
            @Suppress("UNCHECKED_CAST")
            // TestViewModel is a basic ViewModel that sets a String variable
            return TestViewModel(args) as T
        }
    }
}
// Create a ViewModel using the custom factory passing in the custom extras
val viewModel = customFactory.create(TestViewModel::class.java, extras)
// The value from the extras is now available in the ViewModel
viewModel.args
Parameters
viewModelStoreOwner: ViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) { "No ViewModelStoreOwner was provided via LocalViewModelStoreOwner" }

The owner of the ViewModel that controls the scope and lifetime of the returned ViewModel. Defaults to using LocalViewModelStoreOwner.

key: String? = null

The key to use to identify the ViewModel.

factory: ViewModelProvider.Factory? = null

The ViewModelProvider.Factory that should be used to create the ViewModel or null if you would like to use the default factory from the LocalViewModelStoreOwner

extras: CreationExtras = viewModelStoreOwner.defaultViewModelCreationExtras

The default extras used to create the ViewModel.

Returns
VM

A ViewModel that is an instance of the given VM type.

@Composable
fun <VM : ViewModel> viewModel(
    modelClass: Class<VM>,
    viewModelStoreOwner: ViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) { "No ViewModelStoreOwner was provided via LocalViewModelStoreOwner" },
    key: String? = null,
    factory: ViewModelProvider.Factory? = null,
    extras: CreationExtras = viewModelStoreOwner.defaultViewModelCreationExtras
): VM

Returns an existing ViewModel or creates a new one in the scope (usually, a fragment or an activity)

The created ViewModel is associated with the given viewModelStoreOwner and will be retained as long as the scope is alive (e.g. if it is an activity, until it is finished or process is killed).

If default arguments are provided via the CreationExtras, they will be available to the appropriate factory when the ViewModel is created.

import androidx.compose.runtime.remember
import androidx.core.os.bundleOf
import androidx.lifecycle.DEFAULT_ARGS_KEY
import androidx.lifecycle.HasDefaultViewModelProviderFactory
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.MutableCreationExtras
import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
import androidx.lifecycle.viewmodel.compose.viewModel

val owner = LocalViewModelStoreOwner.current
val defaultExtras =
    (owner as? HasDefaultViewModelProviderFactory)?.defaultViewModelCreationExtras
        ?: CreationExtras.Empty
// Custom extras should always be added on top of the default extras
val extras = MutableCreationExtras(defaultExtras)
extras[DEFAULT_ARGS_KEY] =
    @Suppress("DEPRECATION") // bundleOf is deprecated
    bundleOf("test" to "my_value")
// This factory is normally created separately and passed in
val customFactory = remember {
    object : ViewModelProvider.Factory {
        override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T {
            val args = extras[DEFAULT_ARGS_KEY]?.getString("test")
            @Suppress("UNCHECKED_CAST")
            // TestViewModel is a basic ViewModel that sets a String variable
            return TestViewModel(args) as T
        }
    }
}
// Create a ViewModel using the custom factory passing in the custom extras
val viewModel = customFactory.create(TestViewModel::class.java, extras)
// The value from the extras is now available in the ViewModel
viewModel.args
Parameters
modelClass: Class<VM>

The class of the ViewModel to create an instance of it if it is not present.

viewModelStoreOwner: ViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) { "No ViewModelStoreOwner was provided via LocalViewModelStoreOwner" }

The scope that the created ViewModel should be associated with.

key: String? = null

The key to use to identify the ViewModel.

factory: ViewModelProvider.Factory? = null

The ViewModelProvider.Factory that should be used to create the ViewModel or null if you would like to use the default factory from the LocalViewModelStoreOwner

extras: CreationExtras = viewModelStoreOwner.defaultViewModelCreationExtras

The default extras used to create the ViewModel.

Returns
VM

A ViewModel that is an instance of the given VM type.

@Composable
fun <VM : ViewModel> viewModel(
    modelClass: KClass<VM>,
    viewModelStoreOwner: ViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) { "No ViewModelStoreOwner was provided via LocalViewModelStoreOwner" },
    key: String? = null,
    factory: ViewModelProvider.Factory? = null,
    extras: CreationExtras = viewModelStoreOwner.defaultViewModelCreationExtras
): VM

Returns an existing ViewModel or creates a new one in the scope (usually, a fragment or an activity)

The created ViewModel is associated with the given viewModelStoreOwner and will be retained as long as the scope is alive (e.g. if it is an activity, until it is finished or process is killed).

If default arguments are provided via the CreationExtras, they will be available to the appropriate factory when the ViewModel is created.

import androidx.compose.runtime.remember
import androidx.core.os.bundleOf
import androidx.lifecycle.DEFAULT_ARGS_KEY
import androidx.lifecycle.HasDefaultViewModelProviderFactory
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.MutableCreationExtras
import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
import androidx.lifecycle.viewmodel.compose.viewModel

val owner = LocalViewModelStoreOwner.current
val defaultExtras =
    (owner as? HasDefaultViewModelProviderFactory)?.defaultViewModelCreationExtras
        ?: CreationExtras.Empty
// Custom extras should always be added on top of the default extras
val extras = MutableCreationExtras(defaultExtras)
extras[DEFAULT_ARGS_KEY] =
    @Suppress("DEPRECATION") // bundleOf is deprecated
    bundleOf("test" to "my_value")
// This factory is normally created separately and passed in
val customFactory = remember {
    object : ViewModelProvider.Factory {
        override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T {
            val args = extras[DEFAULT_ARGS_KEY]?.getString("test")
            @Suppress("UNCHECKED_CAST")
            // TestViewModel is a basic ViewModel that sets a String variable
            return TestViewModel(args) as T
        }
    }
}
// Create a ViewModel using the custom factory passing in the custom extras
val viewModel = customFactory.create(TestViewModel::class.java, extras)
// The value from the extras is now available in the ViewModel
viewModel.args
Parameters
modelClass: KClass<VM>

The class of the ViewModel to create an instance of it if it is not present.

viewModelStoreOwner: ViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) { "No ViewModelStoreOwner was provided via LocalViewModelStoreOwner" }

The scope that the created ViewModel should be associated with.

key: String? = null

The key to use to identify the ViewModel.

factory: ViewModelProvider.Factory? = null

The ViewModelProvider.Factory that should be used to create the ViewModel or null if you would like to use the default factory from the LocalViewModelStoreOwner

extras: CreationExtras = viewModelStoreOwner.defaultViewModelCreationExtras

The default extras used to create the ViewModel.

Returns
VM

A ViewModel that is an instance of the given VM type.

Extension functions

@SavedStateHandleSaveableApi
fun <T : Any> SavedStateHandle.saveable(
    saver: Saver<T, Any> = autoSaver(),
    init: () -> T
): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, T>>

Inter-opt between SavedStateHandle and Saver so that any state holder that is being saved via androidx.compose.runtime.saveable.rememberSaveable with a custom Saver can also be saved with SavedStateHandle.

The key is automatically retrieved as the name of the property this delegate is being used to create.

The returned state T should be the only way that a value is saved or restored from the SavedStateHandle with the automatic key.

Using the same key again with another SavedStateHandle method is not supported, as values won't cross-set or communicate updates.

import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.listSaver
import androidx.compose.runtime.toMutableStateList
import androidx.compose.runtime.toMutableStateMap
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewmodel.compose.SavedStateHandleSaveableApi
import androidx.lifecycle.viewmodel.compose.saveable

/** A simple item that is not inherently [Parcelable] */
data class Item(val id: UUID, val value: String)

@OptIn(SavedStateHandleSaveableApi::class)
class SnapshotStateViewModel(handle: SavedStateHandle) : ViewModel() {

    /**
     * A snapshot-backed [MutableList] of a list of items, persisted by the [SavedStateHandle].
     * The size of this set must remain small in expectation, since the maximum size of saved
     * instance state space is limited.
     */
    private val items: MutableList<Item> by
        handle.saveable(
            saver =
                listSaver(
                    save = { it.map { item -> listOf(item.id.toString(), item.value) } },
                    restore = {
                        it.map { saved ->
                                Item(id = UUID.fromString(saved[0]), value = saved[1])
                            }
                            .toMutableStateList()
                    },
                )
        ) {
            mutableStateListOf()
        }

    /**
     * A snapshot-backed [MutableMap] representing a set of selected item ids, persisted by the
     * [SavedStateHandle]. A [MutableSet] is approximated by ignoring the keys. The size of this
     * set must remain small in expectation, since the maximum size of saved instance state
     * space is limited.
     */
    private val selectedItemIds: MutableMap<UUID, Unit> by
        handle.saveable(
            saver =
                listSaver(
                    save = { it.keys.map(UUID::toString) },
                    restore = {
                        it.map(UUID::fromString).map { id -> id to Unit }.toMutableStateMap()
                    },
                )
        ) {
            mutableStateMapOf()
        }

    /**
     * A snapshot-backed flag representing where selections are enabled, persisted by the
     * [SavedStateHandle].
     */
    var areSelectionsEnabled by handle.saveable { mutableStateOf(true) }

    /** A list of items paired with a selection state. */
    val selectedItems: List<Pair<Item, Boolean>>
        get() = items.map { it to (it.id in selectedItemIds) }

    /** Updates the selection state for the item with [id] to [selected]. */
    fun selectItem(id: UUID, selected: Boolean) {
        if (selected) {
            selectedItemIds[id] = Unit
        } else {
            selectedItemIds.remove(id)
        }
    }

    /** Adds an item with the given [value]. */
    fun addItem(value: String) {
        items.add(Item(UUID.randomUUID(), value))
    }
}
@SavedStateHandleSaveableApi
fun <T : Any?, M : MutableState<T>> SavedStateHandle.saveable(
    stateSaver: Saver<T, Any> = autoSaver(),
    init: () -> M
): PropertyDelegateProvider<Any?, ReadWriteProperty<Any?, T>>

Inter-opt between SavedStateHandle and Saver so that any state holder that is being saved via androidx.compose.runtime.saveable.rememberSaveable with a custom Saver can also be saved with SavedStateHandle.

The key is automatically retrieved as the name of the property this delegate is being used to create.

The delegated MutableState should be the only way that a value is saved or restored from the SavedStateHandle with the automatic key.

Using the same key again with another SavedStateHandle method is not supported, as values won't cross-set or communicate updates.

Use this overload to allow delegating to a mutable state just like you can with rememberSaveable:

var value by savedStateHandle.saveable { mutableStateOf("initialValue") }
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.listSaver
import androidx.compose.runtime.toMutableStateList
import androidx.compose.runtime.toMutableStateMap
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewmodel.compose.SavedStateHandleSaveableApi
import androidx.lifecycle.viewmodel.compose.saveable

/** A simple item that is not inherently [Parcelable] */
data class Item(val id: UUID, val value: String)

@OptIn(SavedStateHandleSaveableApi::class)
class SnapshotStateViewModel(handle: SavedStateHandle) : ViewModel() {

    /**
     * A snapshot-backed [MutableList] of a list of items, persisted by the [SavedStateHandle].
     * The size of this set must remain small in expectation, since the maximum size of saved
     * instance state space is limited.
     */
    private val items: MutableList<Item> by
        handle.saveable(
            saver =
                listSaver(
                    save = { it.map { item -> listOf(item.id.toString(), item.value) } },
                    restore = {
                        it.map { saved ->
                                Item(id = UUID.fromString(saved[0]), value = saved[1])
                            }
                            .toMutableStateList()
                    },
                )
        ) {
            mutableStateListOf()
        }

    /**
     * A snapshot-backed [MutableMap] representing a set of selected item ids, persisted by the
     * [SavedStateHandle]. A [MutableSet] is approximated by ignoring the keys. The size of this
     * set must remain small in expectation, since the maximum size of saved instance state
     * space is limited.
     */
    private val selectedItemIds: MutableMap<UUID, Unit> by
        handle.saveable(
            saver =
                listSaver(
                    save = { it.keys.map(UUID::toString) },
                    restore = {
                        it.map(UUID::fromString).map { id -> id to Unit }.toMutableStateMap()
                    },
                )
        ) {
            mutableStateMapOf()
        }

    /**
     * A snapshot-backed flag representing where selections are enabled, persisted by the
     * [SavedStateHandle].
     */
    var areSelectionsEnabled by handle.saveable { mutableStateOf(true) }

    /** A list of items paired with a selection state. */
    val selectedItems: List<Pair<Item, Boolean>>
        get() = items.map { it to (it.id in selectedItemIds) }

    /** Updates the selection state for the item with [id] to [selected]. */
    fun selectItem(id: UUID, selected: Boolean) {
        if (selected) {
            selectedItemIds[id] = Unit
        } else {
            selectedItemIds.remove(id)
        }
    }

    /** Adds an item with the given [value]. */
    fun addItem(value: String) {
        items.add(Item(UUID.randomUUID(), value))
    }
}
@SavedStateHandleSaveableApi
fun <T : Any> SavedStateHandle.saveable(
    key: String,
    saver: Saver<T, Any> = autoSaver(),
    init: () -> T
): T

Inter-opt between SavedStateHandle and Saver so that any state holder that is being saved via androidx.compose.runtime.saveable.rememberSaveable with a custom Saver can also be saved with SavedStateHandle.

The returned state T should be the only way that a value is saved or restored from the SavedStateHandle with the given key.

Using the same key again with another SavedStateHandle method is not supported, as values won't cross-set or communicate updates.

import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.listSaver
import androidx.compose.runtime.toMutableStateList
import androidx.compose.runtime.toMutableStateMap
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewmodel.compose.SavedStateHandleSaveableApi
import androidx.lifecycle.viewmodel.compose.saveable

/** A simple item that is not inherently [Parcelable] */
data class Item(val id: UUID, val value: String)

@OptIn(SavedStateHandleSaveableApi::class)
class SnapshotStateViewModel(handle: SavedStateHandle) : ViewModel() {

    /**
     * A snapshot-backed [MutableList] of a list of items, persisted by the [SavedStateHandle].
     * The size of this set must remain small in expectation, since the maximum size of saved
     * instance state space is limited.
     */
    private val items: MutableList<Item> =
        handle.saveable(
            key = "items",
            saver =
                listSaver(
                    save = { it.map { item -> listOf(item.id.toString(), item.value) } },
                    restore = {
                        it.map { saved ->
                                Item(id = UUID.fromString(saved[0]), value = saved[1])
                            }
                            .toMutableStateList()
                    },
                ),
        ) {
            mutableStateListOf()
        }

    /**
     * A snapshot-backed [MutableMap] representing a set of selected item ids, persisted by the
     * [SavedStateHandle]. A [MutableSet] is approximated by ignoring the keys. The size of this
     * set must remain small in expectation, since the maximum size of saved instance state
     * space is limited.
     */
    private val selectedItemIds: MutableMap<UUID, Unit> =
        handle.saveable(
            key = "selectedItemIds",
            saver =
                listSaver(
                    save = { it.keys.map(UUID::toString) },
                    restore = {
                        it.map(UUID::fromString).map { id -> id to Unit }.toMutableStateMap()
                    },
                ),
        ) {
            mutableStateMapOf()
        }

    /**
     * A snapshot-backed flag representing where selections are enabled, persisted by the
     * [SavedStateHandle].
     */
    var areSelectionsEnabled by handle.saveable("areSelectionsEnabled") { mutableStateOf(true) }

    /** A list of items paired with a selection state. */
    val selectedItems: List<Pair<Item, Boolean>>
        get() = items.map { it to (it.id in selectedItemIds) }

    /** Updates the selection state for the item with [id] to [selected]. */
    fun selectItem(id: UUID, selected: Boolean) {
        if (selected) {
            selectedItemIds[id] = Unit
        } else {
            selectedItemIds.remove(id)
        }
    }

    /** Adds an item with the given [value]. */
    fun addItem(value: String) {
        items.add(Item(UUID.randomUUID(), value))
    }
}
@SavedStateHandleSaveableApi
fun <T : Any?> SavedStateHandle.saveable(
    key: String,
    stateSaver: Saver<T, Any>,
    init: () -> MutableState<T>
): MutableState<T>

Inter-opt between SavedStateHandle and Saver so that any state holder that is being saved via androidx.compose.runtime.saveable.rememberSaveable with a custom Saver can also be saved with SavedStateHandle.

The returned MutableState should be the only way that a value is saved or restored from the SavedStateHandle with the given key.

Using the same key again with another SavedStateHandle method is not supported, as values won't cross-set or communicate updates.

Use this overload if you remember a mutable state with a type which can't be stored in the Bundle so you have to provide a custom saver object.

import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.listSaver
import androidx.compose.runtime.toMutableStateList
import androidx.compose.runtime.toMutableStateMap
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewmodel.compose.SavedStateHandleSaveableApi
import androidx.lifecycle.viewmodel.compose.saveable

/** A simple item that is not inherently [Parcelable] */
data class Item(val id: UUID, val value: String)

@OptIn(SavedStateHandleSaveableApi::class)
class SnapshotStateViewModel(handle: SavedStateHandle) : ViewModel() {

    /**
     * A snapshot-backed [MutableList] of a list of items, persisted by the [SavedStateHandle].
     * The size of this set must remain small in expectation, since the maximum size of saved
     * instance state space is limited.
     */
    private val items: MutableList<Item> =
        handle.saveable(
            key = "items",
            saver =
                listSaver(
                    save = { it.map { item -> listOf(item.id.toString(), item.value) } },
                    restore = {
                        it.map { saved ->
                                Item(id = UUID.fromString(saved[0]), value = saved[1])
                            }
                            .toMutableStateList()
                    },
                ),
        ) {
            mutableStateListOf()
        }

    /**
     * A snapshot-backed [MutableMap] representing a set of selected item ids, persisted by the
     * [SavedStateHandle]. A [MutableSet] is approximated by ignoring the keys. The size of this
     * set must remain small in expectation, since the maximum size of saved instance state
     * space is limited.
     */
    private val selectedItemIds: MutableMap<UUID, Unit> =
        handle.saveable(
            key = "selectedItemIds",
            saver =
                listSaver(
                    save = { it.keys.map(UUID::toString) },
                    restore = {
                        it.map(UUID::fromString).map { id -> id to Unit }.toMutableStateMap()
                    },
                ),
        ) {
            mutableStateMapOf()
        }

    /**
     * A snapshot-backed flag representing where selections are enabled, persisted by the
     * [SavedStateHandle].
     */
    var areSelectionsEnabled by handle.saveable("areSelectionsEnabled") { mutableStateOf(true) }

    /** A list of items paired with a selection state. */
    val selectedItems: List<Pair<Item, Boolean>>
        get() = items.map { it to (it.id in selectedItemIds) }

    /** Updates the selection state for the item with [id] to [selected]. */
    fun selectItem(id: UUID, selected: Boolean) {
        if (selected) {
            selectedItemIds[id] = Unit
        } else {
            selectedItemIds.remove(id)
        }
    }

    /** Adds an item with the given [value]. */
    fun addItem(value: String) {
        items.add(Item(UUID.randomUUID(), value))
    }
}

Top-level properties

ViewModelStoreOwnerHostDefaultKey

val ViewModelStoreOwnerHostDefaultKeyHostDefaultKey<ViewModelStoreOwner?>

A HostDefaultKey used to retrieve the ViewModelStoreOwner provided by the current hosting environment.

This key allows the composition to access the host's ViewModelStoreOwner through a decoupled mechanism, typically used by compositionLocalWithHostDefaultOf.

On platforms where a ViewModelStoreOwner is not present or supported, this may resolve to null.