mattinger
01/05/2022, 4:13 PMmattinger
01/05/2022, 4:18 PMclass PodOnboardingViewModel(savedStateHandle: SavedStateHandle): ViewModel() {
private val _state: MutableState<PodOnboardingState> =
mutableStateOf(PodOnboardingState())
val state: State<PodOnboardingState>
get() = _state
init {
val restored: PodOnboardingState? = savedStateHandle.get(KEY)
restored?.let { _state.value = it }
val stateFlow = snapshotFlow { state.value }
viewModelScope.launch {
stateFlow.collect { current ->
savedStateHandle.set(KEY, current)
}
}
}
companion object {
private val KEY = "PodOnboardingViewModel.state"
}
}mattinger
01/05/2022, 4:25 PMmattinger
01/05/2022, 4:40 PMclass SavingMutableState<T>(
initialValue: T,
private val savedStateHandle: SavedStateHandle,
private val key: String
): MutableState<T> {
private val internalState: MutableState<T> =
mutableStateOf(initialValue)
init {
val previousValue: T? = savedStateHandle.get(key)
if (previousValue == null) {
internalState.value = initialValue
savedStateHandle.set(key, initialValue)
} else {
internalState.value = previousValue
}
}
override var value: T
get() = internalState.value
set(value) {
internalState.value = value
savedStateHandle.set(key, value)
}
override fun component1(): T =
value
override fun component2(): (T) -> Unit = {
value = it
}
}Alex Vanyo
01/05/2022, 4:53 PMK Merle
01/05/2022, 4:56 PMval state: State<PodOnboardingState>
get() = _statemattinger
01/05/2022, 5:08 PMvar serialNumber: String?
get() { return _state.value.serialNumber }
set(value) { _state.value = _state.value.copy(serialNumber = value) }K Merle
01/05/2022, 5:12 PMval state: State<PodOnboardingState> = _state the same?mattinger
01/05/2022, 5:14 PMmattinger
01/05/2022, 5:14 PMK Merle
01/05/2022, 5:15 PMmattinger
01/05/2022, 5:15 PMIan Lake
01/05/2022, 6:32 PMmattinger
01/05/2022, 8:50 PMIan Lake
01/05/2022, 8:52 PMmattinger
01/05/2022, 8:53 PMIan Lake
01/05/2022, 8:54 PMT can actually be put in a SavedStateHandle directly while the code I provided supports any type of T by using the Saver APIsmattinger
01/05/2022, 8:55 PMmattinger
01/05/2022, 8:58 PMIan Lake
01/05/2022, 8:59 PMrememberSaveable 🙂mattinger
01/05/2022, 9:01 PMmattinger
01/05/2022, 9:02 PMmattinger
01/05/2022, 10:17 PMAlex Vanyo
01/05/2022, 10:26 PMSavedStateHandle is just a plain class that you can instantiate directly for tests, so you should be able to construct one directly with whatever state you need via SavedStateHandle(initialState: Map<String, Any>) or modifying it before passing it to the `ViewModel`’s constructor.mattinger
01/05/2022, 10:27 PMmattinger
01/05/2022, 10:27 PMwith(autoSaver<PodOnboardingState>()) {
val saverScope = SaverScope { true }
savedStateHandle.set(
PodOnboardingViewModel.KEY,
bundleOf("value" to saverScope.save(PodOnboardingState(serialNumber = "1")))
)
}mattinger
01/05/2022, 10:31 PMIan Lake
01/05/2022, 10:51 PMautoSaver() isn't going to do anything to a Parcelable when you save it, it just returns that exact object back so none of that saverScope code should be necessary (see: https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/[…]onMain/kotlin/androidx/compose/runtime/saveable/Saver.kt;l=96)mattinger
01/06/2022, 2:25 PMmRegular field, which doesn’t have an entry for the providers. It just seems odd because the keys() function does look in there:mattinger
01/06/2022, 2:26 PM@MainThread
@NonNull
public Set<String> keys() {
HashSet<String> allKeys = new HashSet<>(mRegular.keySet());
allKeys.addAll(mSavedStateProviders.keySet());
allKeys.addAll(mLiveDatas.keySet());
return allKeys;
}
@MainThread
@Nullable
public <T> T get(@NonNull String key) {
return (T) mRegular.get(key);
}mattinger
01/06/2022, 2:31 PMIan Lake
01/06/2022, 4:30 PMvar directly if you want the in process value - that's the source of truthAlex Vanyo
01/06/2022, 9:30 PMsave manually for testing purposes, if you wanted to verify that some Saver did the right thing (for instance).
It looks like that’s almost there with SavedStateHandle.savedStateProvider() , but that isn’t public.Alex Vanyo
01/06/2022, 9:33 PMStateRestorationTester and expect that everywhere 😄