Overview
What is SavedStateFlow?
SavedStateFlow is a Kotlin StateFlow that can survive the Android process death.
Why SavedStateFlow?
SavedStateHandle is a great tool to persist state across the Android process death, however this only officially supports reactive updates through LiveData. There is a nice extension function that exists in the support library that can convert LiveData to a Flow, however using this directly in a ViewModel test requires setting up the test to work with LiveData and LiveData can technically have a null value.
This is where SavedStateFlow comes in being a simple wrapper around SavedStateHandle.getLiveData() while enabling non null initial values exposing the state as a StateFlow.
Basic Usage
Inject a SavedStateFlowHandle into a ViewModel by using the extension function on SavedStateHandle.
val savedStateHandle: SavedStateHandle = TODO()
val savedStateFlowHandle: SavedStateFlowHandle =
savedStateHandle.toSavedStateFlowHandle()
Info
Please refer to the samples to see how to get a reference to SavedStateHandle.
- manual injection using the
AbstractSavedStateViewModelFactory - The
saved-state-flow-hiltartifact automatically scopesSavedStateFlowHandletoViewModel's so there is no need to get a reference to aSavedStateHandle.
Once a SavedStateFlowHandle is created, inject it in a ViewModel and retrieve a SavedStateFlow.
class MainViewModel(
savedStateFlowHandle: SavedStateFlowHandle,
private val newsDataSource: NewsDataSource
) : ViewModel() {
private val query: SavedStateFlow<String> =
savedStateFlowHandle.getSavedStateFlow(
viewModelScope = viewModelScope, // scope for updates to be collected
key = "main-viewmodel-query-key", // unique key for the property
defaultValue = "" // used when there is no previously saved value upon restoration
)
init {
observeQuery()
}
fun updateQuery(query: String) {
this.query.value = query
}
private fun observeQuery() {
viewModelScope.launch {
query.asStateFlow()
.flatMapLatest { query ->
// fetch the results for the latest query
newsDataSource.fetchQuery(query)
}
.collect { results ->
// Update with the latest results
}
}
}
}
Warning
Since SavedStateFlow is a wrapper around SavedStateHandle, the following note from the documentation should be observed.
State must be simple and lightweight. For complex or large data, you should use local persistence.