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() = _state
mattinger
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 😄