Convert SavedStateRegistry to Kotlin
Part of the kotlinification of SavedState module.
Test: ./gradlew checkApi all existing test pass
Bug: 220191285
Relnote: "SavedStateRegistry is now in Kotlin"
Change-Id: I2539228cdbb20892cb71dcc8f4fecc31cede9486
diff --git a/savedstate/savedstate/api/current.txt b/savedstate/savedstate/api/current.txt
index 6ef8e87..e1371e1 100644
--- a/savedstate/savedstate/api/current.txt
+++ b/savedstate/savedstate/api/current.txt
@@ -2,19 +2,22 @@
package androidx.savedstate {
public final class SavedStateRegistry {
- method @MainThread public android.os.Bundle? consumeRestoredStateForKey(String);
- method public androidx.savedstate.SavedStateRegistry.SavedStateProvider? getSavedStateProvider(String);
+ method @MainThread public android.os.Bundle? consumeRestoredStateForKey(String key);
+ method public androidx.savedstate.SavedStateRegistry.SavedStateProvider? getSavedStateProvider(String key);
method @MainThread public boolean isRestored();
- method @MainThread public void registerSavedStateProvider(String, androidx.savedstate.SavedStateRegistry.SavedStateProvider);
- method @MainThread public void runOnNextRecreation(Class<? extends androidx.savedstate.SavedStateRegistry.AutoRecreated>);
- method @MainThread public void unregisterSavedStateProvider(String);
+ method @MainThread public void performAttach(androidx.lifecycle.Lifecycle lifecycle);
+ method @MainThread public void performRestore(android.os.Bundle? savedState);
+ method @MainThread public void registerSavedStateProvider(String key, androidx.savedstate.SavedStateRegistry.SavedStateProvider provider);
+ method @MainThread public void runOnNextRecreation(Class<? extends androidx.savedstate.SavedStateRegistry.AutoRecreated> clazz);
+ method @MainThread public void unregisterSavedStateProvider(String key);
+ property @MainThread public final boolean isRestored;
}
public static interface SavedStateRegistry.AutoRecreated {
- method public void onRecreated(androidx.savedstate.SavedStateRegistryOwner);
+ method public void onRecreated(androidx.savedstate.SavedStateRegistryOwner owner);
}
- public static interface SavedStateRegistry.SavedStateProvider {
+ public static fun interface SavedStateRegistry.SavedStateProvider {
method public android.os.Bundle saveState();
}
diff --git a/savedstate/savedstate/api/public_plus_experimental_current.txt b/savedstate/savedstate/api/public_plus_experimental_current.txt
index 6ef8e87..e1371e1 100644
--- a/savedstate/savedstate/api/public_plus_experimental_current.txt
+++ b/savedstate/savedstate/api/public_plus_experimental_current.txt
@@ -2,19 +2,22 @@
package androidx.savedstate {
public final class SavedStateRegistry {
- method @MainThread public android.os.Bundle? consumeRestoredStateForKey(String);
- method public androidx.savedstate.SavedStateRegistry.SavedStateProvider? getSavedStateProvider(String);
+ method @MainThread public android.os.Bundle? consumeRestoredStateForKey(String key);
+ method public androidx.savedstate.SavedStateRegistry.SavedStateProvider? getSavedStateProvider(String key);
method @MainThread public boolean isRestored();
- method @MainThread public void registerSavedStateProvider(String, androidx.savedstate.SavedStateRegistry.SavedStateProvider);
- method @MainThread public void runOnNextRecreation(Class<? extends androidx.savedstate.SavedStateRegistry.AutoRecreated>);
- method @MainThread public void unregisterSavedStateProvider(String);
+ method @MainThread public void performAttach(androidx.lifecycle.Lifecycle lifecycle);
+ method @MainThread public void performRestore(android.os.Bundle? savedState);
+ method @MainThread public void registerSavedStateProvider(String key, androidx.savedstate.SavedStateRegistry.SavedStateProvider provider);
+ method @MainThread public void runOnNextRecreation(Class<? extends androidx.savedstate.SavedStateRegistry.AutoRecreated> clazz);
+ method @MainThread public void unregisterSavedStateProvider(String key);
+ property @MainThread public final boolean isRestored;
}
public static interface SavedStateRegistry.AutoRecreated {
- method public void onRecreated(androidx.savedstate.SavedStateRegistryOwner);
+ method public void onRecreated(androidx.savedstate.SavedStateRegistryOwner owner);
}
- public static interface SavedStateRegistry.SavedStateProvider {
+ public static fun interface SavedStateRegistry.SavedStateProvider {
method public android.os.Bundle saveState();
}
diff --git a/savedstate/savedstate/api/restricted_current.txt b/savedstate/savedstate/api/restricted_current.txt
index 6ef8e87..e1371e1 100644
--- a/savedstate/savedstate/api/restricted_current.txt
+++ b/savedstate/savedstate/api/restricted_current.txt
@@ -2,19 +2,22 @@
package androidx.savedstate {
public final class SavedStateRegistry {
- method @MainThread public android.os.Bundle? consumeRestoredStateForKey(String);
- method public androidx.savedstate.SavedStateRegistry.SavedStateProvider? getSavedStateProvider(String);
+ method @MainThread public android.os.Bundle? consumeRestoredStateForKey(String key);
+ method public androidx.savedstate.SavedStateRegistry.SavedStateProvider? getSavedStateProvider(String key);
method @MainThread public boolean isRestored();
- method @MainThread public void registerSavedStateProvider(String, androidx.savedstate.SavedStateRegistry.SavedStateProvider);
- method @MainThread public void runOnNextRecreation(Class<? extends androidx.savedstate.SavedStateRegistry.AutoRecreated>);
- method @MainThread public void unregisterSavedStateProvider(String);
+ method @MainThread public void performAttach(androidx.lifecycle.Lifecycle lifecycle);
+ method @MainThread public void performRestore(android.os.Bundle? savedState);
+ method @MainThread public void registerSavedStateProvider(String key, androidx.savedstate.SavedStateRegistry.SavedStateProvider provider);
+ method @MainThread public void runOnNextRecreation(Class<? extends androidx.savedstate.SavedStateRegistry.AutoRecreated> clazz);
+ method @MainThread public void unregisterSavedStateProvider(String key);
+ property @MainThread public final boolean isRestored;
}
public static interface SavedStateRegistry.AutoRecreated {
- method public void onRecreated(androidx.savedstate.SavedStateRegistryOwner);
+ method public void onRecreated(androidx.savedstate.SavedStateRegistryOwner owner);
}
- public static interface SavedStateRegistry.SavedStateProvider {
+ public static fun interface SavedStateRegistry.SavedStateProvider {
method public android.os.Bundle saveState();
}
diff --git a/savedstate/savedstate/src/main/java/androidx/savedstate/SavedStateRegistry.kt b/savedstate/savedstate/src/main/java/androidx/savedstate/SavedStateRegistry.kt
index 3bca4f1..a8bd28d 100644
--- a/savedstate/savedstate/src/main/java/androidx/savedstate/SavedStateRegistry.kt
+++ b/savedstate/savedstate/src/main/java/androidx/savedstate/SavedStateRegistry.kt
@@ -13,270 +13,259 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package androidx.savedstate
-package androidx.savedstate;
-
-import android.annotation.SuppressLint;
-import android.os.Bundle;
-
-import androidx.annotation.MainThread;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.arch.core.internal.SafeIterableMap;
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleEventObserver;
-
-import java.util.Iterator;
-import java.util.Map;
+import android.annotation.SuppressLint
+import android.os.Bundle
+import androidx.annotation.MainThread
+import androidx.arch.core.internal.SafeIterableMap
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleEventObserver
/**
* An interface for plugging components that consumes and contributes to the saved state.
*
- * <p>This objects lifetime is bound to the lifecycle of owning component: when activity or
+ *
+ * This objects lifetime is bound to the lifecycle of owning component: when activity or
* fragment is recreated, new instance of the object is created as well.
*/
@SuppressLint("RestrictedApi")
-public final class SavedStateRegistry {
- private static final String SAVED_COMPONENTS_KEY =
- "androidx.lifecycle.BundlableSavedStateRegistry.key";
-
- private final SafeIterableMap<String, SavedStateProvider> mComponents =
- new SafeIterableMap<>();
- private boolean mAttached;
- @Nullable
- private Bundle mRestoredState;
- private boolean mRestored;
- private Recreator.SavedStateProvider mRecreatorProvider;
- boolean mAllowingSavingState = true;
-
- SavedStateRegistry() {
- }
+class SavedStateRegistry internal constructor() {
+ private val components = SafeIterableMap<String, SavedStateProvider>()
+ private var attached = false
+ private var restoredState: Bundle? = null
/**
- * Consumes saved state previously supplied by {@link SavedStateProvider} registered
- * via {@link #registerSavedStateProvider(String, SavedStateProvider)}
- * with the given {@code key}.
- * <p>
+ * Whether the state was restored after creation and can be safely consumed
+ * with [consumeRestoredStateForKey].
+ *
+ * [isRestored] == true if state was restored
+ */
+ @get: MainThread
+ var isRestored = false
+ private set
+ private var recreatorProvider: Recreator.SavedStateProvider? = null
+ internal var isAllowingSavingState = true
+
+ /**
+ * Consumes saved state previously supplied by [SavedStateProvider] registered
+ * via [registerSavedStateProvider] with the given `key`.
+ *
+ *
* This call clears an internal reference to returned saved state, so if you call it second time
- * in the row it will return {@code null}.
- * <p>
- * All unconsumed values will be saved during {@code onSaveInstanceState(Bundle savedState)}
- * <p>
- * This method can be called after {@code super.onCreate(savedStateBundle)} of the corresponding
- * component. Calling it before that will result in {@code IllegalArgumentException}.
- * {@link Lifecycle.Event#ON_CREATE} can be used as a signal
+ * in the row it will return `null`.
+ *
+ *
+ * All unconsumed values will be saved during `onSaveInstanceState(Bundle savedState)`
+ *
+ *
+ * This method can be called after `super.onCreate(savedStateBundle)` of the corresponding
+ * component. Calling it before that will result in `IllegalArgumentException`.
+ * [Lifecycle.Event.ON_CREATE] can be used as a signal
* that a saved state can be safely consumed.
*
- * @param key a key with which {@link SavedStateProvider} was previously registered.
- * @return {@code S} with the previously saved state or {@code null}
+ * @param key a key with which [SavedStateProvider] was previously registered.
+ * @return `S` with the previously saved state or {@code null}
*/
@MainThread
- @Nullable
- public Bundle consumeRestoredStateForKey(@NonNull String key) {
- if (!mRestored) {
- throw new IllegalStateException("You can consumeRestoredStateForKey "
- + "only after super.onCreate of corresponding component");
+ fun consumeRestoredStateForKey(key: String): Bundle? {
+ check(isRestored) {
+ ("You can consumeRestoredStateForKey " +
+ "only after super.onCreate of corresponding component")
}
- if (mRestoredState != null) {
- Bundle result = mRestoredState.getBundle(key);
- mRestoredState.remove(key);
- if (mRestoredState.isEmpty()) {
- mRestoredState = null;
+ if (restoredState != null) {
+ val result = restoredState?.getBundle(key)
+ restoredState?.remove(key)
+ if (restoredState?.isEmpty != false) {
+ restoredState = null
}
- return result;
+ return result
}
- return null;
+ return null
}
/**
- * Registers a {@link SavedStateProvider} by the given {@code key}. This
- * {@code savedStateProvider} will be called
- * during state saving phase, returned object will be associated with the given {@code key}
- * and can be used after the restoration via {@link #consumeRestoredStateForKey(String)}.
- * <p>
- * If there is unconsumed value with the same {@code key},
- * the value supplied by {@code savedStateProvider} will be override and
+ * Registers a [SavedStateProvider] by the given `key`. This
+ * `savedStateProvider` will be called
+ * during state saving phase, returned object will be associated with the given `key`
+ * and can be used after the restoration via [.consumeRestoredStateForKey].
+ *
+ *
+ * If there is unconsumed value with the same `key`,
+ * the value supplied by `savedStateProvider` will be overridden and
* will be written to resulting saved state.
- * <p> if a provider was already registered with the given {@code key}, an implementation should
- * throw an {@link IllegalArgumentException}
+ *
+ * If a provider was already registered with the given `key`, an implementation should
+ * throw an [IllegalArgumentException]
*
* @param key a key with which returned saved state will be associated
* @param provider savedStateProvider to get saved state.
*/
@MainThread
- public void registerSavedStateProvider(@NonNull String key,
- @NonNull SavedStateProvider provider) {
- SavedStateProvider previous = mComponents.putIfAbsent(key, provider);
- if (previous != null) {
- throw new IllegalArgumentException("SavedStateProvider with the given key is"
- + " already registered");
+ fun registerSavedStateProvider(
+ key: String,
+ provider: SavedStateProvider
+ ) {
+ val previous = components.putIfAbsent(key, provider)
+ require(previous == null) {
+ ("SavedStateProvider with the given key is" +
+ " already registered")
}
}
/**
- * Get a previously registered {@link SavedStateProvider}.
+ * Get a previously registered [SavedStateProvider].
*
- * @param key The key used to register the {@link SavedStateProvider} when it was registered
- * with {@link #registerSavedStateProvider(String, SavedStateProvider)}.
- * @return The {@link SavedStateProvider} previously registered with
- * {@link #registerSavedStateProvider(String, SavedStateProvider)} or null if no provider
+ * @param key The key used to register the [SavedStateProvider] when it was registered
+ * with registerSavedStateProvider(String, SavedStateProvider).
+ *
+ * Returns the [SavedStateProvider] previously registered with
+ * [registerSavedStateProvider] or null if no provider
* has been registered with the given key.
- * @see #registerSavedStateProvider(String, SavedStateProvider)
*/
- @Nullable
- public SavedStateProvider getSavedStateProvider(@NonNull String key) {
- SavedStateProvider provider = null;
- for (Map.Entry<String, SavedStateProvider> entry : mComponents) {
- if (entry.getKey().equals(key)) {
- provider = entry.getValue();
- break;
+ fun getSavedStateProvider(key: String): SavedStateProvider? {
+ var provider: SavedStateProvider? = null
+ for ((k, value) in components) {
+ if (k == key) {
+ provider = value
+ break
}
}
- return provider;
+ return provider
}
/**
- * Unregisters a component previously registered by the given {@code key}
+ * Unregisters a component previously registered by the given `key`
*
* @param key a key with which a component was previously registered.
*/
@MainThread
- public void unregisterSavedStateProvider(@NonNull String key) {
- mComponents.remove(key);
- }
-
- /**
- * Returns if state was restored after creation and can be safely consumed
- * with {@link #consumeRestoredStateForKey(String)}
- *
- * @return true if state was restored.
- */
- @MainThread
- public boolean isRestored() {
- return mRestored;
+ fun unregisterSavedStateProvider(key: String) {
+ components.remove(key)
}
/**
* Subclasses of this interface will be automatically recreated if they were previously
- * registered via {@link #runOnNextRecreation(Class)}.
- * <p>
+ * registered via [runOnNextRecreation].
+ *
+ *
* Subclasses must have a default constructor
*/
- public interface AutoRecreated {
+ interface AutoRecreated {
/**
* This method will be called during
- * dispatching of {@link androidx.lifecycle.Lifecycle.Event#ON_CREATE} of owning component.
+ * dispatching of [androidx.lifecycle.Lifecycle.Event.ON_CREATE] of owning component
+ * which was restarted
*
* @param owner a component that was restarted
*/
- void onRecreated(@NonNull SavedStateRegistryOwner owner);
+ fun onRecreated(owner: SavedStateRegistryOwner)
}
/**
* Executes the given class when the owning component restarted.
- * <p>
+ *
+ *
* The given class will be automatically instantiated via default constructor and method
- * {@link AutoRecreated#onRecreated(SavedStateRegistryOwner)} will be called.
- * It is called as part of dispatching of {@link androidx.lifecycle.Lifecycle.Event#ON_CREATE}
+ * [AutoRecreated.onRecreated] will be called.
+ * It is called as part of dispatching of [androidx.lifecycle.Lifecycle.Event.ON_CREATE]
* event.
*
* @param clazz that will need to be instantiated on the next component recreation
- * @throws IllegalStateException if you try to call if after {@link Lifecycle.Event#ON_STOP}
+ * @throws IllegalArgumentException if you try to call if after [Lifecycle.Event.ON_STOP]
* was dispatched
*/
@MainThread
- public void runOnNextRecreation(@NonNull Class<? extends AutoRecreated> clazz) {
- if (!mAllowingSavingState) {
- throw new IllegalStateException(
- "Can not perform this action after onSaveInstanceState");
- }
- if (mRecreatorProvider == null) {
- mRecreatorProvider = new Recreator.SavedStateProvider(this);
- }
+ fun runOnNextRecreation(clazz: Class<out AutoRecreated>) {
+ check(isAllowingSavingState) { "Can not perform this action after onSaveInstanceState" }
+ recreatorProvider = recreatorProvider ?: Recreator.SavedStateProvider(this)
try {
- clazz.getDeclaredConstructor();
- } catch (NoSuchMethodException e) {
- throw new IllegalArgumentException("Class" + clazz.getSimpleName() + " must have "
- + "default constructor in order to be automatically recreated", e);
+ clazz.getDeclaredConstructor()
+ } catch (e: NoSuchMethodException) {
+ throw IllegalArgumentException(
+ "Class ${clazz.simpleName} must have " +
+ "default constructor in order to be automatically recreated", e
+ )
}
- mRecreatorProvider.add(clazz.getName());
+ recreatorProvider?.add(clazz.name)
}
/**
- * An interface for an owner of this @{code {@link SavedStateRegistry} to attach this
- * to a {@link Lifecycle}.
+ * An interface for an owner of this [SavedStateRegistry] to attach this
+ * to a [Lifecycle].
*/
@MainThread
- void performAttach(@NonNull Lifecycle lifecycle) {
- if (mAttached) {
- throw new IllegalStateException("SavedStateRegistry was already attached.");
- }
+ fun performAttach(lifecycle: Lifecycle) {
+ check(!attached) { "SavedStateRegistry was already attached." }
- lifecycle.addObserver((LifecycleEventObserver) (source, event) -> {
+ lifecycle.addObserver(LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_START) {
- mAllowingSavingState = true;
+ isAllowingSavingState = true
} else if (event == Lifecycle.Event.ON_STOP) {
- mAllowingSavingState = false;
+ isAllowingSavingState = false
}
- });
-
- mAttached = true;
+ })
+ attached = true
}
/**
- * An interface for an owner of this @{code {@link SavedStateRegistry} to restore saved state.
+ * An interface for an owner of this [SavedStateRegistry] to restore saved state.
*
*/
@MainThread
- void performRestore(@Nullable Bundle savedState) {
- if (!mAttached) {
- throw new IllegalStateException("You must call performAttach() before calling "
- + "performRestore(Bundle).");
+ fun performRestore(savedState: Bundle?) {
+ check(attached) {
+ ("You must call performAttach() before calling " +
+ "performRestore(Bundle).")
}
- if (mRestored) {
- throw new IllegalStateException("SavedStateRegistry was already restored.");
- }
- if (savedState != null) {
- mRestoredState = savedState.getBundle(SAVED_COMPONENTS_KEY);
- }
+ check(!isRestored) { "SavedStateRegistry was already restored." }
+ restoredState = savedState?.getBundle(SAVED_COMPONENTS_KEY)
- mRestored = true;
+ isRestored = true
}
/**
- * An interface for an owner of this @{code {@link SavedStateRegistry}
+ * An interface for an owner of this [SavedStateRegistry]
* to perform state saving, it will call all registered providers and
* merge with unconsumed state.
*
* @param outBundle Bundle in which to place a saved state
+ * @suppress INACCESSIBLE_TYPE iterator is used strictly as Iterator, does not access
+ * inaccessible type IteratorWithAdditions
*/
@MainThread
- void performSave(@NonNull Bundle outBundle) {
- Bundle components = new Bundle();
- if (mRestoredState != null) {
- components.putAll(mRestoredState);
+ @Suppress("INACCESSIBLE_TYPE")
+ fun performSave(outBundle: Bundle) {
+ val components = Bundle()
+ if (restoredState != null) {
+ components.putAll(restoredState)
}
- for (Iterator<Map.Entry<String, SavedStateProvider>> it =
- mComponents.iteratorWithAdditions(); it.hasNext(); ) {
- Map.Entry<String, SavedStateProvider> entry1 = it.next();
- components.putBundle(entry1.getKey(), entry1.getValue().saveState());
+ val it: Iterator<Map.Entry<String, SavedStateProvider>> =
+ this.components.iteratorWithAdditions()
+ while (it.hasNext()) {
+ val (key, value) = it.next()
+ components.putBundle(key, value.saveState())
}
- if (!components.isEmpty()) {
- outBundle.putBundle(SAVED_COMPONENTS_KEY, components);
+ if (!components.isEmpty) {
+ outBundle.putBundle(SAVED_COMPONENTS_KEY, components)
}
}
/**
* This interface marks a component that contributes to saved state.
*/
- public interface SavedStateProvider {
+ fun interface SavedStateProvider {
/**
* Called to retrieve a state from a component before being killed
- * so later the state can be received from {@link #consumeRestoredStateForKey(String)}
+ * so later the state can be received from [consumeRestoredStateForKey]
*
- * @return S with your saved state.
+ * Returns `S` with your saved state.
*/
- @NonNull
- Bundle saveState();
+ fun saveState(): Bundle
+ }
+
+ private companion object {
+ private const val SAVED_COMPONENTS_KEY =
+ "androidx.lifecycle.BundlableSavedStateRegistry.key"
}
}