Android ViewModels: Saving State across Process Death
A quick recipe on how to save ViewModel state across android process death.
A misconception among some android developers is that the purpose of using ViewModels is state persistence — it’s actually partly true — they do help in saving state across configuration change (e.g. device rotation) but not process death. So if Android kills your app (let’s say because of low memory), then your app state is lost.
So depending on whether you want to persist your state across process death or not — you can either use onSaveInstanceState
in your Fragments/Activities or the new SavedStateHandle
in your ViewModels.
Ok so why SavedStateHandle
and why save/handle states in ViewModels?
Well if you handle your state (for process death) in Activities or Fragments — that’ll add extra verbosity and will cause tight coupling between state-handling & activity/fragment code. Handling your state via ViewModels solves this issue.
Using SavedStateHandle
Add lifecycle-viewmodel-savedstate dependency
dependencies {
def lifecycle_version = "2.2.0" // currently the latest version // Saved state module for ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"}
Add SavedStateHandle property in your ViewModel
class MainViewModel(val state: SavedStateHandle) : ViewModel() {
...
}
Initialize your ViewModel using SavedStateViewModelFactory
class MainFragment : Fragment() {
private val viewModel: MainViewModel by viewModels {
SavedStateViewModelFactory(application, activity)
}...
Saving and restoring state
The SavedStateHandle
has methods for setting/getting values.
get(String key)
contains(String key)
remove(String key)
set(String key, T value)
keys()
You can save/restore primitives, bundles and parcelables.
Saving is as easy as:
// In your viewmodel
fun saveName(name: String) {
state.set("Name", name)
}// In your fragment
viewModel.saveName("Ahmed Rizwan")
And restoring:
// In your viewmodel
fun getName(): String? {
state.get<String>("Name")
}// In your fragment
val name = viewModel.getName()
Restore state as a LiveData
If you want to restore your data as LiveData, theres a getter for that as well.
// In your viewmodel
val nameLiveData = state.getLiveData<String>("Name")// In your activity/fragment
viewModel.nameLiveData.observe(this) { name ->
...
}
And that’s it! Make sure to handle all your states!
Happy coding!