Configuration Changes, State Saving and Process Death
Configuration Changes, State Saving and Process Death
1. What is a configuration change?
A configuration change happens when the device or application environment changes.
Examples:
* Screen rotation
* Language change
* Light or dark theme change
* Font scale change
* Screen size change
* Foldable device state change
* Keyboard availability change
Android normally destroys and recreates the Activity so it can load resources matching the new configuration.
---
2. Rotation flow
Portrait Activity
|
Device rotated
|
onPause()
|
onStop()
|
onDestroy()
|
New landscape Activity
|
onCreate()
|
onStart()
|
onResume()The old Activity object is destroyed.
A new Activity object is created with resources such as:
res/layout/activity_main.xml
res/layout-land/activity_main.xml---
3. Language change
When the application language changes:
Old Activity
|
Destroyed
|
New Activity created
|
Localized resources loadedExample resources:
res/values/strings.xml
res/values-hi/strings.xml
res/values-fr/strings.xml---
4. Theme change
Changing between light and dark mode can also recreate the Activity.
Light theme Activity
|
Night mode changes
|
Activity recreated
|
Dark theme resources loadedResources can come from:
values/themes.xml
values-night/themes.xml---
5. ViewModel retention
ViewModel survives configuration changes.
Activity A
|
Rotation
|
Activity A destroyed
|
Activity B created
|
Same ViewModel returnedclass ProductViewModel : ViewModel() {
var selectedProductId: String? = null
}Obtain it:
private val viewModel: ProductViewModel by viewModels()ViewModel survives
* Rotation
* Language-related Activity recreation
* Theme-related Activity recreation
* Other normal configuration changes
ViewModel does not survive
* System process death
* App force-stop
* Normal final Activity finish
* Device reboot
---
6. Saved instance state
savedInstanceState stores small UI-related values.
private var selectedTab = 0
override fun onSaveInstanceState(outState: Bundle) {
outState.putInt("selected_tab", selectedTab)
super.onSaveInstanceState(outState)
}Restore:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
selectedTab =
savedInstanceState?.getInt("selected_tab") ?: 0
}Saved state can help restore UI after both configuration changes and system-initiated process death, but Bundles should contain only small, serializable state.
Good saved-state values:
* Selected tab
* Scroll position
* Search query
* Entered text
* Selected item ID
* Filter option
Bad saved-state values:
* Large API responses
* Bitmaps
* Complete database lists
* Repository objects
* Network clients
---
7. SavedStateHandle
SavedStateHandle provides saved state inside a ViewModel.
class SearchViewModel(
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
val query = savedStateHandle.getStateFlow(
"search_query",
""
)
fun updateQuery(value: String) {
savedStateHandle["search_query"] = value
}
}It combines two useful behaviors:
ViewModel
Survives configuration changes
SavedStateHandle
Restores small values after process recreationSavedStateHandle is suitable for small reconstruction information such as IDs, queries and filters—not for storing large business data.
---
8. Process death
During process death, all in-memory objects are lost.
Activity -> Lost
Fragment -> Lost
ViewModel -> Lost
Application object -> Lost
Singleton -> Lost
Static variables -> Lost
Coroutine scopes -> LostPersistent or saved data may remain:
Saved instance state -> Restorable
SavedStateHandle -> Restorable
Room -> Remains
DataStore -> Remains
Files -> Remain
Server data -> Remains---
9. Correct state reconstruction
Instead of saving complete data, save enough information to reload it.
Bad:
savedStateHandle["complete_product"] = largeProductObjectBetter:
savedStateHandle["product_id"] = product.idThen reconstruct:
Saved product ID
|
New ViewModel created
|
Read product ID
|
Repository loads product
|
Room/API provides latest data
|
UI state rebuiltExample:
class ProductViewModel(
savedStateHandle: SavedStateHandle,
repository: ProductRepository
) : ViewModel() {
private val productId: String =
checkNotNull(savedStateHandle["product_id"])
val product = repository.observeProduct(productId)
}---
10. Process death testing
Method 1: ADB process kill
1. Open the required application screen.
2. Press Home so the app moves to the background.
3. Run:
adb shell am kill com.example.app4. Open the app again from the launcher or Recents.
5. Check whether state is reconstructed.
Android’s lifecycle codelab uses this approach to simulate the system killing a background process.
Method 2: “Don’t keep activities”
Enable:
Developer options
|
Don't keep activitiesThis destroys Activities when the user leaves them.
Important:
> “Don’t keep activities” is useful for finding Activity recreation problems, but it is not exactly the same as full application process death.
Avoid force-stop for normal restoration testing
Force-stop represents a user-directed app dismissal. Saved task state might not be restored in the same way as system-initiated process death.---
11. State-management decision table
| Requirement | Solution |
|---|---|
| Survive rotation | ViewModel |
| Restore small UI state | Saved instance state |
| Save state inside ViewModel | SavedStateHandle |
| Save structured business data | Room |
| Save settings | DataStore |
| Save large data | Database, file or server |
| Reliable background operation | WorkManager |
| Restore screen | Saved ID + repository reload |
---
Interview answer
> Configuration changes normally destroy and recreate the Activity. ViewModel survives configuration changes but does not survive process death. Small UI values can be saved using saved instance state or SavedStateHandle. Important or large business data should be stored in Room, DataStore, files or a server. After process death, the app should reconstruct the screen using saved IDs, queries or filters and reload the real data from a repository.