forked from androidx/androidx
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge "Add property delegates to support saving and restoring seriali…
…zable data with SavedStateHandle" into androidx-main
- Loading branch information
Showing
11 changed files
with
419 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
52 changes: 52 additions & 0 deletions
52
lifecycle/lifecycle-viewmodel-savedstate-samples/build.gradle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/* | ||
* Copyright (C) 2024 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. | ||
*/ | ||
|
||
/** | ||
* This file was created using the `create_project.py` script located in the | ||
* `<AndroidX root>/development/project-creator` directory. | ||
* | ||
* Please use that script when creating a new project, rather than copying an existing project and | ||
* modifying its settings. | ||
*/ | ||
|
||
import androidx.build.KotlinTarget | ||
import androidx.build.LibraryType | ||
|
||
plugins { | ||
id("AndroidXPlugin") | ||
id("com.android.library") | ||
id("org.jetbrains.kotlin.android") | ||
alias(libs.plugins.kotlinSerialization) | ||
} | ||
|
||
dependencies { | ||
api(libs.kotlinStdlib) | ||
compileOnly(project(":annotation:annotation-sampled")) | ||
implementation(project(":lifecycle:lifecycle-viewmodel")) | ||
implementation(project(":lifecycle:lifecycle-viewmodel-savedstate")) | ||
} | ||
|
||
android { | ||
namespace "androidx.lifecycle.viewmodel.savedstate.samples" | ||
} | ||
|
||
androidx { | ||
name = "androidx.lifecycle:lifecycle-viewmodel-savedstate-samples" | ||
type = LibraryType.SAMPLES | ||
inceptionYear = "2024" | ||
description = "Lifecycle ViewModel SavedState Samples" | ||
kotlinTarget = KotlinTarget.KOTLIN_1_9 | ||
} |
59 changes: 59 additions & 0 deletions
59
...avedstate-samples/src/main/java/androidx/lifecycle/LifecycleViewModelSavedStateSamples.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/* | ||
* Copyright 2024 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.lifecycle | ||
|
||
import androidx.annotation.Sampled | ||
import kotlinx.serialization.InternalSerializationApi | ||
import kotlinx.serialization.Serializable | ||
import kotlinx.serialization.serializer | ||
|
||
@Sampled | ||
fun delegate() { | ||
@Serializable data class User(val id: Int, val name: String) | ||
class ProfileViewModel(savedStateHandle: SavedStateHandle) : ViewModel() { | ||
val user by savedStateHandle.saved { User(123, "foo") } | ||
} | ||
} | ||
|
||
@Sampled | ||
fun delegateExplicitKey() { | ||
@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") } | ||
} | ||
} | ||
|
||
@OptIn(InternalSerializationApi::class) | ||
@Sampled | ||
fun delegateExplicitSerializer() { | ||
@Serializable data class User(val id: Int, val name: String) | ||
class ProfileViewModel(savedStateHandle: SavedStateHandle) : ViewModel() { | ||
val user by savedStateHandle.saved(User::class.serializer()) { User(123, "foo") } | ||
} | ||
} | ||
|
||
@OptIn(InternalSerializationApi::class) | ||
@Sampled | ||
fun delegateExplicitKeyAndSerializer() { | ||
@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") | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,3 +42,7 @@ final val androidx.lifecycle/VIEW_MODEL_STORE_OWNER_KEY // androidx.lifecycle/VI | |
|
||
final fun (androidx.lifecycle.viewmodel/CreationExtras).androidx.lifecycle/createSavedStateHandle(): androidx.lifecycle/SavedStateHandle // androidx.lifecycle/createSavedStateHandle|createSavedStateHandle@androidx.lifecycle.viewmodel.CreationExtras(){}[0] | ||
final fun <#A: androidx.lifecycle/ViewModelStoreOwner & androidx.savedstate/SavedStateRegistryOwner> (#A).androidx.lifecycle/enableSavedStateHandles() // androidx.lifecycle/enableSavedStateHandles|enableSavedStateHandles@0:0(){0§<androidx.savedstate.SavedStateRegistryOwner&androidx.lifecycle.ViewModelStoreOwner>}[0] | ||
final fun <#A: kotlin/Any> (androidx.lifecycle/SavedStateHandle).androidx.lifecycle/saved(kotlin/String, kotlinx.serialization/KSerializer<#A>, kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.lifecycle/saved|[email protected](kotlin.String;kotlinx.serialization.KSerializer<0:0>;kotlin.Function0<0:0>){0§<kotlin.Any>}[0] | ||
final fun <#A: kotlin/Any> (androidx.lifecycle/SavedStateHandle).androidx.lifecycle/saved(kotlinx.serialization/KSerializer<#A>, kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.lifecycle/saved|[email protected](kotlinx.serialization.KSerializer<0:0>;kotlin.Function0<0:0>){0§<kotlin.Any>}[0] | ||
final inline fun <#A: reified kotlin/Any> (androidx.lifecycle/SavedStateHandle).androidx.lifecycle/saved(kotlin/String, noinline kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.lifecycle/saved|[email protected](kotlin.String;kotlin.Function0<0:0>){0§<kotlin.Any>}[0] | ||
final inline fun <#A: reified kotlin/Any> (androidx.lifecycle/SavedStateHandle).androidx.lifecycle/saved(noinline kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.lifecycle/saved|[email protected](kotlin.Function0<0:0>){0§<kotlin.Any>}[0] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
139 changes: 139 additions & 0 deletions
139
...del-savedstate/src/androidInstrumentedTest/kotlin/androidx/lifecycle/SerializationTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
/* | ||
* 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.lifecycle | ||
|
||
import androidx.activity.ComponentActivity | ||
import androidx.test.ext.junit.rules.ActivityScenarioRule | ||
import androidx.test.ext.junit.runners.AndroidJUnit4 | ||
import androidx.test.filters.SmallTest | ||
import com.google.common.truth.Truth.assertThat | ||
import kotlinx.serialization.builtins.serializer | ||
import org.junit.Rule | ||
import org.junit.Test | ||
import org.junit.runner.RunWith | ||
|
||
@SmallTest | ||
@RunWith(AndroidJUnit4::class) | ||
class SerializationTest { | ||
|
||
@get:Rule val activityTestRuleScenario = ActivityScenarioRule(ComponentActivity::class.java) | ||
|
||
@Test | ||
fun simpleRestore() { | ||
activityTestRuleScenario.scenario.onActivity { activity -> | ||
val viewModel: MyViewModel = ViewModelProvider(activity)[MyViewModel::class] | ||
var value by viewModel.savedStateHandle.saved { 1 } | ||
assertThat(value).isEqualTo(1) | ||
value = 2 | ||
assertThat(value).isEqualTo(2) | ||
} | ||
activityTestRuleScenario.scenario.recreate() | ||
activityTestRuleScenario.scenario.onActivity { activity -> | ||
val viewModel: MyViewModel = ViewModelProvider(activity)[MyViewModel::class] | ||
var value: Int by | ||
viewModel.savedStateHandle.saved { error("Unexpected initializer call") } | ||
assertThat(value).isEqualTo(2) | ||
} | ||
} | ||
|
||
@Test | ||
fun explicitKey() { | ||
activityTestRuleScenario.scenario.onActivity { activity -> | ||
val viewModel: MyViewModel = ViewModelProvider(activity)[MyViewModel::class] | ||
var value by viewModel.savedStateHandle.saved(key = "foo") { 1 } | ||
assertThat(value).isEqualTo(1) | ||
value = 2 | ||
assertThat(value).isEqualTo(2) | ||
} | ||
activityTestRuleScenario.scenario.recreate() | ||
activityTestRuleScenario.scenario.onActivity { activity -> | ||
val viewModel: MyViewModel = ViewModelProvider(activity)[MyViewModel::class] | ||
var value: Int by | ||
viewModel.savedStateHandle.saved(key = "foo") { | ||
error("Unexpected initializer call") | ||
} | ||
assertThat(value).isEqualTo(2) | ||
} | ||
} | ||
|
||
@Test | ||
fun explicitSerializer() { | ||
activityTestRuleScenario.scenario.onActivity { activity -> | ||
val viewModel: MyViewModel = ViewModelProvider(activity)[MyViewModel::class] | ||
val value by viewModel.savedStateHandle.saved(serializer = Int.serializer()) { 1 } | ||
assertThat(value).isEqualTo(1) | ||
} | ||
activityTestRuleScenario.scenario.recreate() | ||
activityTestRuleScenario.scenario.onActivity { activity -> | ||
val viewModel: MyViewModel = ViewModelProvider(activity)[MyViewModel::class] | ||
val value: Int by | ||
viewModel.savedStateHandle.saved(serializer = Int.serializer()) { | ||
error("Unexpected initializer call") | ||
} | ||
assertThat(value).isEqualTo(1) | ||
} | ||
} | ||
|
||
@Test | ||
fun explicitKeyAndSerializer() { | ||
activityTestRuleScenario.scenario.onActivity { activity -> | ||
val viewModel: MyViewModel = ViewModelProvider(activity)[MyViewModel::class] | ||
val value by | ||
viewModel.savedStateHandle.saved(key = "foo", serializer = Int.serializer()) { 1 } | ||
assertThat(value).isEqualTo(1) | ||
} | ||
activityTestRuleScenario.scenario.recreate() | ||
activityTestRuleScenario.scenario.onActivity { activity -> | ||
val viewModel: MyViewModel = ViewModelProvider(activity)[MyViewModel::class] | ||
val value: Int by | ||
viewModel.savedStateHandle.saved(key = "foo", serializer = Int.serializer()) { | ||
error("Unexpected initializer call") | ||
} | ||
assertThat(value).isEqualTo(1) | ||
} | ||
} | ||
|
||
@Test | ||
fun duplicateKeys() { | ||
activityTestRuleScenario.scenario.onActivity { activity -> | ||
val viewModel: MyViewModel = ViewModelProvider(activity)[MyViewModel::class] | ||
val serializable by viewModel.savedStateHandle.saved(key = "foo") { 1 } | ||
assertThat(serializable).isEqualTo(1) | ||
val duplicate by viewModel.savedStateHandle.saved(key = "foo") { 2 } | ||
assertThat(duplicate).isEqualTo(2) | ||
// The value is from the initializer. | ||
assertThat(serializable).isEqualTo(1) | ||
} | ||
activityTestRuleScenario.scenario.recreate() | ||
activityTestRuleScenario.scenario.onActivity { activity -> | ||
val viewModel: MyViewModel = ViewModelProvider(activity)[MyViewModel::class] | ||
val serializable: Int by | ||
viewModel.savedStateHandle.saved(key = "foo") { | ||
error("Unexpected initializer call") | ||
} | ||
assertThat(serializable).isEqualTo(2) | ||
val duplicate: Int by | ||
viewModel.savedStateHandle.saved(key = "foo") { | ||
error("Unexpected initializer call") | ||
} | ||
assertThat(duplicate).isEqualTo(2) | ||
assertThat(serializable).isEqualTo(2) | ||
} | ||
} | ||
} | ||
|
||
class MyViewModel(val savedStateHandle: SavedStateHandle) : ViewModel() |
Oops, something went wrong.