State Restoration is a mechanism of mobile operating systems that allows saving and restoring the application user interface after it is restarted or minimized. The system saves the UI state to memory or persistent storage and restores it when reopened. According to Android Developers (2025), State Restoration is essential for applications striving for a quality user experience. State Restoration is critical for preventing data loss when an application terminates unexpectedly.
Key Takeaways
State Restoration is a system mechanism that allows saving the current state of the application user interface and restoring it after termination or restart. When a user minimizes an app or the system closes it to free resources, State Restoration captures key UI parameters and saves them to encrypted storage.
Without State Restoration, users lose all unsaved data when switching between apps. For example, a filled-out feedback form, a long search query, or a partially viewed news list — all of this disappears on restart. State Restoration solves this problem by automatically capturing the ViewController or Activity state at the moment of minimizing.
The mechanism works at the system level and is supported by both major mobile platforms. iOS provides State Restoration via NSUserActivity and the UIStateRestoring protocol, while Android provides it via SavedStateHandle in Jetpack architectural components and ViewModel. The implementation differs, but the concept is identical.
The State Restoration process is divided into two phases: save and restore. In the save phase, the system calls the corresponding lifecycle methods, in which the application must serialize the current UI state into a compact representation. In the restore phase, the system passes the saved data back, and the application deserializes it to restore the UI.
Saving is initiated by the system when the app moves to the background or receives a signal of imminent termination. On iOS, the encodeRestorableState method of UIViewController is called; on Android, onSaveInstanceState of Activity or saving via SavedStateHandle is triggered. Data is serialized into a format supporting primitive types: strings, numbers, byte arrays, and Parcelable objects.
The amount of saved data should be minimal — the system imposes limits on the size of the saved state bundle. On Android, the limit is approximately 50 KB per process. Exceeding the limit throws a TransactionTooLargeException. Therefore, architects recommend saving only identifiers and keys, and loading full data from persistent storage upon restoration.
During restoration, the system passes the saved data bundle to the app at launch time. On iOS, the decodeRestorableState method is called; on Android, onRestoreInstanceState or reading from SavedStateHandle is used. The app extracts identifiers and keys from the bundle and restores the UI: scroll position, selected items, entered data.
It is important to note that restoration can occur in a new process. If the app was completely unloaded from memory, the process is created anew, and all in-memory objects are absent. Therefore, the state must be serializable and independent of the runtime context of the previous session. This is especially critical for large forms with multiple input fields and long multi-page interfaces.
class MainActivity : AppCompatActivity() {
private var searchQuery: String = ""
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString("search_query", searchQuery)
}
override fun onRestoreInstanceState(savedState: Bundle) {
super.onRestoreInstanceState(savedState)
searchQuery = savedState.getString("search_query", "")!!
restoreSearchUI(searchQuery)
}
}
The implementation of State Restoration differs significantly between platforms. iOS uses a declarative approach via storyboards and UIKit protocols, while Android uses an imperative approach through Activity lifecycle methods and Jetpack architectural components. The choice of approach depends on the target platform and application architecture.
In iOS, State Restoration is built on three components: UIApplication manages the overall process, UIViewController implements the UIStateRestoring protocol, and NSUserActivity stores data for navigation restoration. To enable it, you must set the restorationIdentifier on UIViewController and implement encodeRestorableState and decodeRestorableState.
iOS automatically saves the state of the navigation controller (UINavigationController) and all nested ViewControllers if they have a restorationIdentifier set. The system manages the navigation stack and restores it to its original state. However, data inside controllers (entered text, scroll position) must be explicitly saved by the developer.
In Android, the modern approach to State Restoration is built on SavedStateHandle — a component from the AndroidX Lifecycle library. SavedStateHandle is accessible inside ViewModel and automatically saves and restores data on configuration changes (screen rotation) and process restart. Data is stored in a Bundle and automatically serialized.
SavedStateHandle behaves like a key-value store with LiveData support. On configuration changes, data is saved and restored automatically. To support process restart, the ViewModel must be created via SavedStateViewModelFactory — this allows the ViewModel to survive complete app termination.
class SearchViewModel(
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
companion object {
private val KEY_QUERY = string("search_query")
}
fun getSearchQuery(): String? = savedStateHandle[KEY_QUERY]
fun saveSearchQuery(query: String) {
savedStateHandle[KEY_QUERY] = query
}
}
Practical implementation of State Restoration requires considering several aspects: choosing the right storage, determining the amount of data to save, and testing various termination scenarios. Let us walk through a step-by-step implementation for a Flutter application using the state_restoration package.
class RestorableSearchField extends RestorableProperty<String> {
String _value = '';
@override
String get value => _value;
@override
void set value(String newValue) {
if (_value != newValue) {
_value = newValue;
notifyListeners();
}
}
@override
String? toPrimitives() => _value;
@override
void fromPrimitives(String? data) {
_value = data ?? '';
}
}
When implementing, it is important to remember save boundaries. Not every UI field needs to be restored. A scroll position in a long list — yes. A temporary animation state — no. The developer must consciously choose which data is critical for the user experience and which can be safely reset without loss of convenience.
Testing State Restoration is a separate task that requires simulating process termination. On Android, this can be done via the adb shell am kill command; on iOS, via termination simulation in Xcode. UI testing frameworks such as Espresso and XCTest provide special methods for verifying state restoration.
The first rule — save identifiers, not data. Instead of saving the full object with a hundred fields, save its unique identifier, and on restoration load the actual data from the database or API. This saves space in the Bundle and guarantees data freshness at the time of restoration.
The second rule — test all scenarios. Check restoration after screen rotation, after minimizing and returning an hour later, after the system terminates the app due to low memory. Each scenario may behave differently depending on the operating system state and available resources.
The third rule — use system mechanisms, not custom ones. iOS and Android provide built-in APIs for State Restoration that are optimized for their specific platform. A custom implementation via SharedPreferences or UserDefaults can lead to synchronization issues and unexpected behavior during restoration.
The fourth rule — handle missing state. On first launch or after data clearing, the state may be absent. The UI must work correctly in its initial state without throwing exceptions. Check all saved data for null before use and provide default values.
The fifth rule — document saved keys. When a project has dozens of screens and each saves several fields, without centralized key management chaos ensues. Create a single class or file with key constants for State Restoration in each module. This simplifies maintenance and prevents accidental data overwrites during refactoring.
Frequently Asked Questions
State Restoration is a mechanism for saving and restoring the application user interface after it is restarted or minimized, preventing loss of data and user context.
State Restoration saves temporary UI state (scroll position, form input data), while a database stores persistent user data. State Restoration uses system mechanisms (Bundle, NSData) with volume limitations.
Use SavedStateHandle in ViewModel from AndroidX Lifecycle. It automatically saves data on minimize and restores it on return. For full restart support, use SavedStateViewModelFactory.
Set restorationIdentifier on UIViewController and implement encodeRestorableState and decodeRestorableState methods. For navigation, use NSUserActivity with path preservation in the controller stack.
Save identifiers, not full data: selected item ID, search query, scroll position, toggle states. Avoid saving large objects and images.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also