# SavedStateHandle

Artifact: [androidx.lifecycle:lifecycle-viewmodel-savedstate](https://developer.android.com/jetpack/androidx/releases/lifecycle.md.txt) [View Source](https://cs.android.com/search?q=file:androidx/lifecycle/SavedStateHandle.+class:androidx.lifecycle.SavedStateHandle) Added in [2.3.0](https://developer.android.com/jetpack/androidx/releases/lifecycle.md.txt#2.3.0)

*** ** * ** ***

Common/AllAndroid/JVM
- Cmn

  ```
  class SavedStateHandle
  ```

*** ** * ** ***

A handle to saved state passed to `ViewModel`. Typically, `SavedStateViewModelFactory` provides this object to the `ViewModel` constructor.

A key-value map allowing retrieval and storage of values to and from the saved state. These values persist through system-initiated process death and remain available to the recreated instance.

Values can be read via `get` or observed as a flow via `getStateFlow`. Values can be written via `set` or by updating the returned flow via `getMutableStateFlow`.

## Summary

| ### Nested types |
|---|
| `object SavedStateHandle.Companion` |

| ### Public constructors |
|---|---|
| `@VisibleForTesting SavedStateHandle()` Creates a handle with the empty state. | Cmn android |
| `@VisibleForTesting SavedStateHandle(initialState: Map<String, Any?>)` Creates a handle with the given initial arguments. | Cmn android |

| ### Public functions |
|---|---|---|
| `SavedStateContainer` | `@MainThread asContainer()` Returns the underlying `SavedStateContainer` managing this `SavedStateHandle`. | Cmn android |
| `Unit` | `@MainThread clearSavedStateProvider(key: String)` Clear any `SavedStateProvider` that was previously set via `setSavedStateProvider`. | Cmn android |
| `operator Boolean` | `@MainThread contains(key: String)` | Cmn android |
| `operator T?` | `@MainThread <T : Any?> get(key: String)` Returns a value associated with the given key. | Cmn android |
| `MutableLiveData<T>` | `@MainThread <T : Any?> getLiveData(key: String)` Returns a `LiveData` that accesses data associated with the given `key`. | android |
| `MutableLiveData<T>` | `@MainThread <T : Any?> getLiveData(key: String, initialValue: T)` Returns a `LiveData` that accesses data associated with the given `key`. | android |
| `MutableStateFlow<T>` | `@MainThread <T : Any?> getMutableStateFlow(key: String, initialValue: T)` Returns a `MutableStateFlow` that will emit the currently active value associated with the given key. | Cmn android |
| `SavedStateContainer` | `@MainThread getOrCreateContainer(key: String)` Retrieves an existing nested `SavedStateContainer` associated with `key`, or creates and registers a new child `SavedStateContainer` if none exists. | Cmn android |
| `SavedStateHandle` | `@MainThread getOrCreateSavedStateHandle(key: String)` Retrieves an existing nested `SavedStateHandle` associated with `key`, or creates and registers a new child `SavedStateHandle` backed by the child container if none exists. | Cmn android |
| `StateFlow<T>` | `@MainThread <T : Any?> getStateFlow(key: String, initialValue: T)` Returns a `StateFlow` that will emit the currently active value associated with the given key. | Cmn android |
| `Set<String>` | `@MainThread keys()` Returns all keys contained in this `SavedStateHandle` | Cmn android |
| `T?` | `@MainThread <T : Any?> remove(key: String)` Removes a value associated with the given key. | Cmn android |
| `operator Unit` | `@MainThread <T : Any?> set(key: String, value: T?)` Associate the given value with the key. | Cmn android |
| `Unit` | `@MainThread setSavedStateProvider( key: String, provider: SavedStateRegistry.SavedStateProvider )` Sets a `SavedStateProvider` that will have its state saved into this `SavedStateHandle`. | Cmn android |

| ### Extension functions |
|---|---|---|
| `inline ReadWriteProperty<Any?, T>` | `<T : Any?> SavedStateHandle.saved( key: String?, configuration: SavedStateConfiguration, noinline init: () -> T )` Returns a property delegate that uses `SavedStateHandle` to save and restore a value of type `T` with the default serializer. | Cmn |
| `ReadWriteProperty<Any?, T>` | `<T : Any?> SavedStateHandle.saved( serializer: KSerializer<T>, key: String?, configuration: SavedStateConfiguration, init: () -> T )` Returns a property delegate that uses `SavedStateHandle` to save and restore a value of type `T`. | Cmn |
| `inline T` | `<T : Any> SavedStateHandle.toRoute(typeMap: Map<KType, NavType<*>>)` Returns route as an object of type `T` | Cmn |
| `T` | `<T : Any> SavedStateHandle.toRoute( route: KClass<T>, typeMap: Map<KType, NavType<*>> )` Returns route as an object of type `T` | Cmn |
| `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 |

## Public constructors

### SavedStateHandle

Cmn android Added in [2.3.0](https://developer.android.com/jetpack/androidx/releases/lifecycle.md.txt#2.3.0)

```
@VisibleForTesting
SavedStateHandle()
```

Creates a handle with the empty state.

**Important:** This constructor should only be used directly in tests. The created `SavedStateHandle` is not bound to the current `SavedStateRegistryOwner`, meaning its internal state will not be restored in the event of a process death.

In production, use `viewModelFactory` or implement `ViewModelProvider.Factory` directly, using `CreationExtras.createSavedStateHandle` to create a `SavedStateHandle` that is bound with the current `SavedStateRegistryOwner`.

### SavedStateHandle

Cmn android Added in [2.3.0](https://developer.android.com/jetpack/androidx/releases/lifecycle.md.txt#2.3.0)

```
@VisibleForTesting
SavedStateHandle(initialState: Map<String, Any?>)
```

Creates a handle with the given initial arguments.

**Important:** This constructor should only be used directly in tests. The created `SavedStateHandle` is not bound to the current `SavedStateRegistryOwner`, meaning its internal state will not be restored in the event of a process death.

In production, use `viewModelFactory` or implement `ViewModelProvider.Factory` directly, using `CreationExtras.createSavedStateHandle` to create a `SavedStateHandle` that is bound to the current `SavedStateRegistryOwner`.

| Parameters |
|---|---|
| `initialState: Map<String, Any?>` | initial arguments for the SavedStateHandle |

## Public functions

### asContainer

Cmn android Added in [2.12.0-alpha05](https://developer.android.com/jetpack/androidx/releases/lifecycle.md.txt#2.12.0-alpha05)

```
@MainThread
fun asContainer(): SavedStateContainer
```

Returns the underlying `SavedStateContainer` managing this `SavedStateHandle`.

### clearSavedStateProvider

Cmn android Added in [2.3.0](https://developer.android.com/jetpack/androidx/releases/lifecycle.md.txt#2.3.0)

```
@MainThread
fun clearSavedStateProvider(key: String): Unit
```

Clear any `SavedStateProvider` that was previously set via `setSavedStateProvider`.

Note: calling this method within `SavedStateProvider.saveState` is supported, but will only affect future state saving operations.

| Parameters |
|---|---|
| `key: String` | identifier previously used with `setSavedStateProvider` |

### contains

Cmn android Added in [2.3.0](https://developer.android.com/jetpack/androidx/releases/lifecycle.md.txt#2.3.0)

```
@MainThread
operator fun contains(key: String): Boolean
```

| Parameters |
|---|---|
| `key: String` | identifier of the value |

| Returns |
|---|---|
| `Boolean` | `true` if a value is associated with `key` |

### get

Cmn android Added in [2.3.0](https://developer.android.com/jetpack/androidx/releases/lifecycle.md.txt#2.3.0)

```
@MainThread
operator fun <T : Any?> get(key: String): T?
```

Returns a value associated with the given key.

Note: If `T` is an `Array` of `android.os.Parcelable` classes, note that you should always use `Array<Parcelable>` and create a typed array from the result as going through process death and recreation (or using the `Don't keep activities` developer option) will result in the type information being lost, thus resulting in a `ClassCastException` if you directly try to assign the result to an `Array<CustomParcelable>` value.

val typedArray = savedStateHandle.get\>("KEY").map { it as CustomParcelable }.toTypedArray()

| Parameters |
|---|---|
| `key: String` | identifier of the value |

### getLiveData

android Added in [2.3.0](https://developer.android.com/jetpack/androidx/releases/lifecycle.md.txt#2.3.0)

```
@MainThread
fun <T : Any?> getLiveData(key: String): MutableLiveData<T>
```

Returns a `LiveData` that accesses data associated with the given `key`.

| Parameters |
|---|---|
| `key: String` | identifier of the value |

| See also |
|---|---|
| `getLiveData` |   |

### getLiveData

android Added in [2.3.0](https://developer.android.com/jetpack/androidx/releases/lifecycle.md.txt#2.3.0)

```
@MainThread
fun <T : Any?> getLiveData(key: String, initialValue: T): MutableLiveData<T>
```

Returns a `LiveData` that accesses data associated with the given `key`.

```kotlin
val liveData = savedStateHandle.getLiveData(KEY, "defaultValue")
```

Note that `LiveData` can have `null` as a valid value. If the `initialValue` is `null` and the data does not already exist in the `SavedStateHandle`, the value of the returned `LiveData` will be set to `null` and observers will be notified. You can call `getLiveData` to avoid dispatching `null` to observers.

```kotlin
val defaultValue = ... // nullable
val liveData = if (defaultValue != null) {
    savedStateHandle.getLiveData(KEY, defaultValue)
} else {
    savedStateHandle.getLiveData(KEY)
}
```

If `T` is an `Array` of `Parcelable` classes, you should always use `Array<Parcelable>` and create a typed array from the result. Going through process death and recreation (or using the "Don't keep activities" developer option) will result in the type information being lost, causing a `ClassCastException` if you directly try to observe the result as `Array<CustomParcelable>`.

```kotlin
val typedArrayLiveData = savedStateHandle.getLiveData<Array<Parcelable>>(
    "KEY"
).map { array ->
    // Convert the Array<Parcelable> to an Array<CustomParcelable>
    array.map { it as CustomParcelable }.toTypedArray()
}
```

| Parameters |
|---|---|
| `key: String` | identifier of the value |
| `initialValue: T` | value to use if no value is associated with `key` |

### getMutableStateFlow

Cmn android Added in [2.9.0](https://developer.android.com/jetpack/androidx/releases/lifecycle.md.txt#2.9.0)

```
@MainThread
fun <T : Any?> getMutableStateFlow(key: String, initialValue: T): MutableStateFlow<T>
```

Returns a `MutableStateFlow` that will emit the currently active value associated with the given key.

val flow = savedStateHandle.getMutableStateFlow(KEY, "defaultValue")

Since this is a `MutableStateFlow` there will always be a value available which, is why an initial value must be provided. The value of this flow is changed by making a call to `set`, passing in the key that references this flow or by updating the value of the returned `MutableStateFlow`

If there is already a value associated with the given key, the initial value will be ignored.

**Note 1:** If `T` is an `Array` of `Parcelable` classes, note that you should always use `Array<Parcelable>` and create a typed array from the result as going through process death and recreation (or using the `Don't keep activities` developer option) will result in the type information being lost, thus resulting in a `ClassCastException` if you directly try to collect the result as an `Array<CustomParcelable>`.

val typedArrayFlow = savedStateHandle.getMutableStateFlow\>( "KEY" ).map { array -\> // Convert the Array to an Array array.map { it as CustomParcelable }.toTypedArray() }

**Note 2:** On Android, this method is mutually exclusive with `getLiveData` for the same key. You should use either `getMutableStateFlow` or `getLiveData` to access the stored value, but not both. Using both methods with the same key will result in an `IllegalStateException`.

| Parameters |
|---|---|
| `key: String` | identifier of the flow |
| `initialValue: T` | value to use if no value is associated with `key` |

### getOrCreateContainer

Cmn android Added in [2.12.0-alpha05](https://developer.android.com/jetpack/androidx/releases/lifecycle.md.txt#2.12.0-alpha05)

```
@MainThread
fun getOrCreateContainer(key: String): SavedStateContainer
```

Retrieves an existing nested `SavedStateContainer` associated with `key`, or creates and registers a new child `SavedStateContainer` if none exists.

| Parameters |
|---|---|
| `key: String` | identifier of the container |

| Returns |
|---|---|
| `SavedStateContainer` | existing or newly created child `SavedStateContainer` instance |

### getOrCreateSavedStateHandle

Cmn android Added in [2.12.0-alpha05](https://developer.android.com/jetpack/androidx/releases/lifecycle.md.txt#2.12.0-alpha05)

```
@MainThread
fun getOrCreateSavedStateHandle(key: String): SavedStateHandle
```

Retrieves an existing nested `SavedStateHandle` associated with `key`, or creates and registers a new child `SavedStateHandle` backed by the child container if none exists.

| Parameters |
|---|---|
| `key: String` | identifier of the child handle |

| Returns |
|---|---|
| `SavedStateHandle` | existing or newly created child `SavedStateHandle` instance |

### getStateFlow

Cmn android Added in [2.5.0](https://developer.android.com/jetpack/androidx/releases/lifecycle.md.txt#2.5.0)

```
@MainThread
fun <T : Any?> getStateFlow(key: String, initialValue: T): StateFlow<T>
```

Returns a `StateFlow` that will emit the currently active value associated with the given key.

val flow = savedStateHandle.getStateFlow(KEY, "defaultValue")

Since this is a `StateFlow` there will always be a value available which, is why an initial value must be provided. The value of this flow is changed by making a call to `set`, passing in the key that references this flow.

If there is already a value associated with the given key, the initial value will be ignored.

Note: If `T` is an `Array` of `android.os.Parcelable` classes, note that you should always use `Array<Parcelable>` and create a typed array from the result as going through process death and recreation (or using the `Don't keep activities` developer option) will result in the type information being lost, thus resulting in a `ClassCastException` if you directly try to collect the result as an `Array<CustomParcelable>`.

```kotlin
val typedArrayFlow = savedStateHandle.getStateFlow<Array<Parcelable>>(
  "KEY"
).map { array ->
  // Convert the Array<Parcelable> to an Array<CustomParcelable>
  array.map { it as CustomParcelable }.toTypedArray()
}
```

| Parameters |
|---|---|
| `key: String` | identifier of the flow |
| `initialValue: T` | value to use if no value is associated with `key` |

### keys

Cmn android Added in [2.3.0](https://developer.android.com/jetpack/androidx/releases/lifecycle.md.txt#2.3.0)

```
@MainThread
fun keys(): Set<String>
```

Returns all keys contained in this `SavedStateHandle`

Returned set contains all keys: keys used to get LiveData-s, to set SavedStateProviders and keys used in regular `set`.

### remove

Cmn android Added in [2.3.0](https://developer.android.com/jetpack/androidx/releases/lifecycle.md.txt#2.3.0)

```
@MainThread
fun <T : Any?> remove(key: String): T?
```

Removes a value associated with the given key. If there is a `androidx.lifecycle.LiveData` and/or `StateFlow` associated with the given key, they will be removed as well.

All changes to `LiveData` or `StateFlow` previously returned by `SavedStateHandle.getLiveData` or `getStateFlow` won't be reflected in the saved state. Also, that `LiveData` or `StateFlow` won't receive any updates about new values associated by the given key.

| Parameters |
|---|---|
| `key: String` | identifier of the value |

| Returns |
|---|---|
| `T?` | value previously associated with `key`, or `null` if none was present |

### set

Cmn android Added in [2.3.0](https://developer.android.com/jetpack/androidx/releases/lifecycle.md.txt#2.3.0)

```
@MainThread
operator fun <T : Any?> set(key: String, value: T?): Unit
```

Associate the given value with the key. The value must have a type that could be stored in `SavedState`

This also sets values for any active `androidx.lifecycle.LiveData` or `StateFlow`.

| Parameters |
|---|---|
| `key: String` | identifier of the value |
| `value: T?` | value to associate with `key` |

| Throws |
|---|---|
| `IllegalArgumentException` | value cannot be saved in saved state |

### setSavedStateProvider

Cmn android Added in [2.3.0](https://developer.android.com/jetpack/androidx/releases/lifecycle.md.txt#2.3.0)

```
@MainThread
fun setSavedStateProvider(
    key: String,
    provider: SavedStateRegistry.SavedStateProvider
): Unit
```

Sets a `SavedStateProvider` that will have its state saved into this `SavedStateHandle`. This provides a mechanism to lazily supply the `SavedState` for the given key.

Calls to `get` with the same key will return the previously saved state as a `SavedState` if it exists.

val previousState: SavedState? = savedStateHandle.get("custom_object") if (previousState != null) { // Convert the previousState into your custom object } savedStateHandle.setSavedStateProvider("custom_object") { savedState { // Put your custom object properties into the SavedState } }

Note: Calling this method within `SavedStateProvider.saveState` is supported, but will only affect future state saving operations.

| Parameters |
|---|---|
| `key: String` | identifier of the state |
| `provider: SavedStateRegistry.SavedStateProvider` | `SavedStateProvider` which will receive a callback to `SavedStateProvider.saveState` when the state should be saved |

## Extension functions

### SavedStateHandle.saved

Cmn Artifact: [androidx.lifecycle:lifecycle-viewmodel-savedstate](https://developer.android.com/jetpack/androidx/releases/lifecycle.md.txt) [View Source](https://cs.android.com/search?q=file:androidx/lifecycle/serialization/SavedStateHandleDelegate.kt+function:saved)

```
inline fun <T : Any?> SavedStateHandle.saved(
    key: String? = null,
    configuration: SavedStateConfiguration = SavedStateConfiguration.DEFAULT,
    noinline init: () -> T
): ReadWriteProperty<Any?, T>
```

Returns a property delegate that uses `SavedStateHandle` to save and restore a value of type `T` with the default serializer.

```kotlin
import androidx.lifecycle.serialization.saved

@Serializable data class User(val id: Int, val name: String)
class ProfileViewModel(savedStateHandle: SavedStateHandle) : ViewModel() {
    val user by savedStateHandle.saved(key = "bar") { User(123, "foo") }
}
```

| Parameters |
|---|---|
| `key: String? = null` | An optional `String` key to use for storing the value in the `SavedStateHandle`. A default key will be generated if it's omitted or when 'null' is passed. |
| `configuration: SavedStateConfiguration = SavedStateConfiguration.DEFAULT` | The `SavedStateConfiguration` to use. Defaults to `SavedStateConfiguration.DEFAULT`. |
| `noinline init: () -> T` | The function to provide the initial value of the property. |

| Returns |
|---|---|
| `ReadWriteProperty<Any?, T>` | A property delegate that manages the saving and restoring of the value. |

### SavedStateHandle.saved

Cmn Artifact: [androidx.lifecycle:lifecycle-viewmodel-savedstate](https://developer.android.com/jetpack/androidx/releases/lifecycle.md.txt) [View Source](https://cs.android.com/search?q=file:androidx/lifecycle/serialization/SavedStateHandleDelegate.kt+function:saved)

```
fun <T : Any?> SavedStateHandle.saved(
    serializer: KSerializer<T>,
    key: String? = null,
    configuration: SavedStateConfiguration = SavedStateConfiguration.DEFAULT,
    init: () -> T
): ReadWriteProperty<Any?, T>
```

Returns a property delegate that uses `SavedStateHandle` to save and restore a value of type `T`.

```kotlin
import androidx.lifecycle.serialization.saved

@Serializable data class User(val id: Int, val name: String)
class ProfileViewModel(savedStateHandle: SavedStateHandle) : ViewModel() {
    val user by
        savedStateHandle.saved(key = "bar", serializer = User::class.serializer()) {
            User(123, "foo")
        }
}
```

| Parameters |
|---|---|
| `serializer: KSerializer<T>` | The `KSerializer` to use for serializing and deserializing the value. |
| `key: String? = null` | An optional `String` key to use for storing the value in the `SavedStateHandle`. A default key will be generated if it's omitted or when 'null' is passed. |
| `configuration: SavedStateConfiguration = SavedStateConfiguration.DEFAULT` | The `SavedStateConfiguration` to use. Defaults to `SavedStateConfiguration.DEFAULT`. |
| `init: () -> T` | The function to provide the initial value of the property. |

| Returns |
|---|---|
| `ReadWriteProperty<Any?, T>` | A property delegate that manages the saving and restoring of the value. |

### SavedStateHandle.toRoute

Cmn Artifact: [androidx.navigation:navigation-common](https://developer.android.com/jetpack/androidx/releases/navigation.md.txt) [View Source](https://cs.android.com/search?q=file:androidx/navigation/SavedStateHandle.kt+function:toRoute)

```
inline fun <T : Any> SavedStateHandle.toRoute(
    typeMap: Map<KType, NavType<*>> = emptyMap()
): T
```

Returns route as an object of type `T`

Extrapolates arguments from `SavedStateHandle` and recreates object `T`

| Parameters |
|---|---|
| `<T : Any>` | the entry's `NavDestination.route` as a `KClass` |
| `typeMap: Map<KType, NavType<*>> = emptyMap()` | A mapping of KType to custom NavType\<\*\> in `T`. May be empty if `T` does not use custom NavTypes. |

| Returns |
|---|---|
| `T` | A new instance of this entry's `NavDestination.route` as an object of type `T` |

### SavedStateHandle.toRoute

Cmn Artifact: [androidx.navigation:navigation-common](https://developer.android.com/jetpack/androidx/releases/navigation.md.txt) [View Source](https://cs.android.com/search?q=file:androidx/navigation/SavedStateHandle.kt+function:toRoute)

```
fun <T : Any> SavedStateHandle.toRoute(
    route: KClass<T>,
    typeMap: Map<KType, NavType<*>> = emptyMap()
): T
```

Returns route as an object of type `T`

Extrapolates arguments from `SavedStateHandle` and recreates object `T`

| Parameters |
|---|---|
| `route: KClass<T>` | the entry's `NavDestination.route` as a `KClass` |
| `typeMap: Map<KType, NavType<*>> = emptyMap()` | A mapping of KType to custom NavType\<\*\> in `T`. May be empty if `T` does not use custom NavTypes. |

| Returns |
|---|---|
| `T` | A new instance of this entry's `NavDestination.route` as an object of type `T` |

### SavedStateHandle.saveable

Cmn Artifact: [androidx.lifecycle:lifecycle-viewmodel-compose](https://developer.android.com/jetpack/androidx/releases/lifecycle.md.txt) [View Source](https://cs.android.com/search?q=file:androidx/lifecycle/viewmodel/compose/SavedStateHandleSaver.kt+function:saveable)

```
@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.

```kotlin
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))
    }
}
```

### SavedStateHandle.saveable

Cmn Artifact: [androidx.lifecycle:lifecycle-viewmodel-compose](https://developer.android.com/jetpack/androidx/releases/lifecycle.md.txt) [View Source](https://cs.android.com/search?q=file:androidx/lifecycle/viewmodel/compose/SavedStateHandleSaver.kt+function:saveable)

```
@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`:

```kotlin
var value by savedStateHandle.saveable { mutableStateOf("initialValue") }
```

```kotlin
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))
    }
}
```

### SavedStateHandle.saveable

Cmn Artifact: [androidx.lifecycle:lifecycle-viewmodel-compose](https://developer.android.com/jetpack/androidx/releases/lifecycle.md.txt) [View Source](https://cs.android.com/search?q=file:androidx/lifecycle/viewmodel/compose/SavedStateHandleSaver.kt+function:saveable)

```
@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.

```kotlin
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))
    }
}
```

### SavedStateHandle.saveable

Cmn Artifact: [androidx.lifecycle:lifecycle-viewmodel-compose](https://developer.android.com/jetpack/androidx/releases/lifecycle.md.txt) [View Source](https://cs.android.com/search?q=file:androidx/lifecycle/viewmodel/compose/SavedStateHandleSaver.kt+function:saveable)

```
@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.

```kotlin
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))
    }
}
```