[go: nahoru, domu]

blob: c48ea618675e24be666c994a81a9e131d7ab82bf [file] [log] [blame]
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.compose.runtime.savedinstancestate
import androidx.compose.staticAmbientOf
/**
* Allows components to save and restore their state using the saved instance state mechanism.
*/
interface UiSavedStateRegistry {
/**
* Returns the restored value for the given key.
* Once being restored the value is cleared, so you can't restore the same key twice.
*
* @param key Key used to save the value
*/
fun consumeRestored(key: String): Any?
/**
* Registers the value provider.
*
* The same [key] cannot be registered twice, if you need to update the provider call
* [unregisterProvider] first and then register again.
*
* @param key Key to use for storing the value
* @param valueProvider Provides the current value, to be executed when [performSave]
* will be triggered to collect all the registered values
*/
fun registerProvider(key: String, valueProvider: () -> Any?)
/**
* Unregisters the value provider previously registered via [registerProvider].
*
* @param key Key of the value which shouldn't be saved anymore
*/
fun unregisterProvider(key: String)
/**
* Returns true if the value can be saved using this Registry.
* The default implementation will return true if this value can be stored in Bundle.
*
* @param value The value which we want to save using this Registry
*/
fun canBeSaved(value: Any): Boolean
/**
* Executes all the registered value providers and combines these values into a key-value map.
*/
fun performSave(): Map<String, Any>
}
/**
* Creates [UiSavedStateRegistry].
*
* @param restoredValues The map of the restored values
* @param canBeSaved Function which returns true if the given value can be saved by the registry
*/
fun UiSavedStateRegistry(
restoredValues: Map<String, Any>?,
canBeSaved: (Any) -> Boolean
): UiSavedStateRegistry = UiSavedStateRegistryImpl(restoredValues, canBeSaved)
/**
* Ambient with a current [UiSavedStateRegistry] instance.
*/
val UiSavedStateRegistryAmbient = staticAmbientOf<UiSavedStateRegistry?> { null }
private class UiSavedStateRegistryImpl(
restored: Map<String, Any>?,
private val canBeSaved: (Any) -> Boolean
) : UiSavedStateRegistry {
private val restored: MutableMap<String, Any> = restored?.toMutableMap() ?: mutableMapOf()
private val valueProviders = mutableMapOf<String, () -> Any?>()
override fun canBeSaved(value: Any): Boolean = canBeSaved.invoke(value)
override fun consumeRestored(key: String): Any? = restored.remove(key)
override fun registerProvider(key: String, valueProvider: () -> Any?) {
require(key.isNotBlank()) { "Registered key is empty or blank" }
require(!valueProviders.contains(key)) {
"Key $key was already registered. Please call " +
"unregister before registering again"
}
@Suppress("UNCHECKED_CAST")
valueProviders[key] = valueProvider
}
override fun unregisterProvider(key: String) {
require(valueProviders.contains(key)) {
"Key $key wasn't registered, but unregister " +
"requested"
}
valueProviders.remove(key)
}
override fun performSave(): Map<String, Any> {
val map = restored.toMutableMap()
valueProviders.forEach {
val value = it.value()
if (value != null) {
check(canBeSaved(value))
map[it.key] = value
}
}
return map
}
}