What happens to SavedStateHandle and your UI state during process death?
Process death silently wipes your ViewModel — SavedStateHandle is the narrow bridge that survives it, and its limits separate a senior answer from a shrug.
LEARN BY DOINGPut your intuition to work3 steps
What happens to SavedStateHandle and your UI state during process death?
Use the lesson’s examples and explanation to check your idea.
Personal reflection. Nothing is sent to an AI service.Two very different disasters get lumped together as "the screen rotated and I lost my data," and only one of them is what a configuration change actually is. Rotating the device, switching to dark mode, or changing the system font size destroys and recreates the Activity, but the process stays alive — the OS never asked the kernel to kill anything. Process death is the other disaster: the app is backgrounded, the system runs low on memory, and the Low Memory Killer (or its equivalent on newer Android versions) simply terminates the process to make room. When the user taps back into the app from Recents, Android launches a brand new process and tries to make it look like nothing happened.
#Why ViewModel alone isn't enough
ViewModel is often introduced as "the thing that survives rotation," and that's true — its backing ViewModelStore is retained across an Activity recreation triggered by a configuration change, because the same process just tears down and rebuilds the UI layer around it. Process death removes that safety net entirely: the process is gone, so the ViewModelStore and every ViewModel instance inside it are gone with it. Whatever ViewModel gets constructed after the user returns starts from a completely empty constructor call.
#The narrow pipe: onSaveInstanceState and the Bundle
Before an Activity becomes eligible to be killed while backgrounded, the system calls onSaveInstanceState(Bundle), giving it one last chance to stash a small amount of state. That Bundle is parceled across a Binder transaction, and Binder transactions share a roughly 1MB buffer across the whole process — stuff too much into it (a full list of search results, a bitmap) and you get a TransactionTooLargeException, sometimes only in production, on the one device with forty open tabs. This is the mechanism SavedStateHandle is built on top of, not a replacement for it.
#Wiring it up
SavedStateHandle is what turns that raw Bundle into something a ViewModel can use safely. The framework (via SavedStateViewModelFactory, or automatically if you use Hilt's @HiltViewModel) hands a ViewModel constructor a SavedStateHandle that is already populated from the restored Bundle, if there was one, and empty otherwise on a genuinely fresh start. Every value you put into it is written straight into that Bundle, so it is ready to be saved the instant the system asks.
@HiltViewModelclass CheckoutViewModel @Inject constructor(private val savedStateHandle: SavedStateHandle,private val repository: CheckoutRepository,) : ViewModel() {// Backed directly by the SavedStateHandle's Bundle — survives process death.val promoCode: StateFlow<String> =savedStateHandle.getStateFlow(KEY_PROMO_CODE, "")private val _uiState = MutableStateFlow(CheckoutUiState())val uiState: StateFlow<CheckoutUiState> = _uiState.asStateFlow()fun onPromoCodeChanged(code: String) {// Writes synchronously into the handle's Bundle — a kill one line// later still restores this exact value on the next process.savedStateHandle[KEY_PROMO_CODE] = code}init {// The cart itself isn't Bundle-friendly, so it is NOT restored here —// it's re-fetched, using the restored promoCode as an input.viewModelScope.launch {val cart = repository.loadCart(promoCode.value)_uiState.update { it.copy(cart = cart) }}}private companion object {const val KEY_PROMO_CODE = "promo_code"}}
Only types that can live inside a Bundle are allowed in — primitives, String, Parcelable, Serializable, and a few collection wrappers of those. Compose has its own sibling mechanism at the composition level, rememberSaveable, which uses the same underlying Bundle machinery through a Saver — useful for state that lives inside a single composable and never needed a ViewModel at all.
#What actually happens, in order
#Proving it, not assuming it
The answer that separates a senior candidate here isn't "ViewModel survives it" — that's the wrong mechanism for the wrong disaster, and it's the single most common wrong answer to this question. The senior answer names both failure modes, explains why ViewModel alone only solves one of them, and knows the size and type constraints that make SavedStateHandle a thin survival layer rather than a persistence layer.