Восстановление состояния (State Restoration) — это механизм мобильных операционных систем, позволяющий сохранять и восстанавливать пользовательский интерфейс приложения после его перезапуска или сворачивания. Система сохраняет состояние UI в память или постоянное хранилище и восстанавливает его при повторном открытии. По данным Android Developers (2025), State Restoration обязателен для приложений, претендующих на качественный пользовательский опыт. State Restoration критически важен для предотвращения потери данных при неожиданном завершении приложения.
Главное
State Restoration (восстановление состояния) — это системный механизм, который позволяет сохранять текущее состояние пользовательского интерфейса приложения и восстанавливать его после завершения или перезапуска. Когда пользователь сворачивает приложение или система закрывает его для освобождения ресурсов, State Restoration фиксирует ключевые параметры UI и сохраняет их в зашифрованном хранилище.
Без State Restoration пользователь теряет все несохранённые данные при переключении между приложениями. Например, заполненная форма обратной связи, длинный поисковый запрос или частично просмотренный список новостей — всё это исчезает при перезапуске. State Restoration решает эту проблему, автоматически фиксируя состояние ViewController или Activity в момент сворачивания.
Механизм работает на системном уровне и поддерживается обеими основными мобильными платформами. iOS предоставляет State Restoration через NSUserActivity и протокол UIStateRestoring, а Android — через SavedStateHandle в архитектурных компонентах Jetpack и ViewModel. Реализация различается, но концепция идентична.
Процесс State Restoration разделяется на две фазы: сохранение (save) и восстановление (restore). На фазе сохранения система вызывает соответствующие методы жизненного цикла, в которых приложение должно сериализовать текущее состояние UI в компактное представление. На фазе восстановления система передаёт сохранённые данные обратно, и приложение десериализует их для восстановления UI.
Сохранение инициируется системой при переходе приложения в фоновый режим или при получении сигнала о скором завершении. В iOS вызывается метод encodeRestorableState у UIViewController, в Android — onSaveInstanceState у Activity или сохранение через SavedStateHandle. Данные сериализуются в формат, поддерживающий примитивные типы: строки, числа, массивы байтов и Parcelable объекты.
Объём сохраняемых данных должен быть минимальным — система накладывает ограничения на размер сохраняемого пакета. В Android лимит составляет примерно 50 КБ на процесс. Превышение лимита приводит к исключению TransactionTooLargeException. Поэтому архитекторы рекомендуют сохранять только идентификаторы и ключи, а полноценные данные загружать из постоянного хранилища при восстановлении.
При восстановлении система передаёт сохранённый пакет данных приложению в момент запуска. В iOS вызывается метод decodeRestorableState, в Android — onRestoreInstanceState или чтение из SavedStateHandle. Приложение извлекает идентификаторы и ключи из пакета и восстанавливает UI: позицию скролла, выбранные элементы, введённые данные.
Важно учитывать, что восстановление может произойти в новом процессе. Если приложение было полностью выгружено из памяти, процесс создаётся заново, и все объекты в памяти отсутствуют. Поэтому состояние должно быть сериализуемым и независимым от рантайм-контекста предыдущей сессии. Особенно это критично для больших форм с множеством полей ввода и длинных многостраничных интерфейсов.
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)
}
}
Реализация State Restoration существенно различается между платформами. iOS использует декларативный подход через storyboard и протоколы UIKit, а Android — императивный через методы жизненного цикла Activity и архитектурные компоненты Jetpack. Выбор подхода зависит от целевой платформы и архитектуры приложения.
В iOS State Restoration строится на трёх компонентах: UIApplication управляет общим процессом, UIViewController реализует протокол UIStateRestoring, а NSUserActivity хранит данные для восстановления навигации. Для включения необходимо установить restorationIdentifier у UIViewController и реализовать encodeRestorableState и decodeRestorableState.
iOS автоматически сохраняет состояние навигационного контроллера (UINavigationController) и всех вложенных ViewController, если у них установлен restorationIdentifier. Система управляет стеком навигации и восстанавливает его в исходном состоянии. Однако данные внутри контроллеров (введённый текст, позиция скролла) должны быть явно сохранены разработчиком.
В Android современный подход к State Restoration строится на SavedStateHandle — компоненте из библиотеки AndroidX Lifecycle. SavedStateHandle доступен внутри ViewModel и автоматически сохраняет и восстанавливает данные при изменении конфигурации (поворот экрана) и при перезапуске процесса. Данные хранятся в Bundle и автоматически сериализуются.
SavedStateHandle ведёт себя как ключ-значение хранилище с поддержкой LiveData. При изменении конфигурации данные сохраняются и восстанавливаются автоматически. Для поддержки перезапуска процесса необходимо, чтобы ViewModel была создана через SavedStateViewModelFactory — это позволяет ViewModel переживать полное завершение приложения.
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
}
}
Практическая реализация State Restoration требует учёта нескольких аспектов: выбор правильного хранилища, определение объёма сохраняемых данных и тестирование различных сценариев завершения. Рассмотрим пошаговую реализацию для Flutter-приложения с использованием пакета state_restoration.
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 ?? '';
}
}
При реализации важно помнить о границах сохранения. Не каждое поле UI нужно восстанавливать. Позиция скролла в длинном списке — да. Временное состояние анимации — нет. Разработчик должен осознанно выбирать, какие данные критичны для пользовательского опыта, а какие можно безопасно сбросить без потери удобства.
Тестирование State Restoration — отдельная задача, требующая имитации завершения процесса. На Android это можно сделать через команду adb shell am kill, на iOS — через симуляцию завершения в Xcode. Фреймворки для UI-тестирования, такие как Espresso и XCTest, предоставляют специальные методы для проверки восстановления состояния.
Первое правило — сохраняйте идентификаторы, а не данные. Вместо того чтобы сохранять полный объект с сотней полей, сохраните его уникальный идентификатор, а при восстановлении загрузите актуальные данные из базы данных или API. Это экономит место в Bundle и гарантирует актуальность данных на момент восстановления.
Второе правило — тестируйте все сценарии. Проверьте восстановление после поворота экрана, после сворачивания и возврата через час, после заверения приложения системой из-за нехватки памяти. Каждый сценарий может вести себя по-разному в зависимости от состояния операционной системы и доступных ресурсов.
Третье правило — используйте системные механизмы, а не собственные. iOS и Android предоставляют встроенные API для State Restoration, которые оптимизированы под конкретную платформу. Собственная реализация через SharedPreferences или UserDefaults может привести к проблемам с синхронизацией и неожиданному поведению при восстановлении.
Четвёртое правило — обрабатывайте отсутствие состояния. При первом запуске или после очистки данных состояние может отсутствовать. UI должен корректно работать в исходном состоянии без выброса исключений. Проверяйте все сохранённые данные на null перед использованием и предусматривайте значения по умолчанию.
Пятое правило — документируйте сохраняемые ключи. Когда в проекте десятки экранов и каждый сохраняет несколько полей, без централизованного управления ключами возникает хаос. Создайте единый класс или файл с константами ключей для State Restoration в каждом модуле. Это упрощает поддержку и предотвращает случайные перезаписи данных при рефакторинге.
Часто задаваемые вопросы
State Restoration — механизм сохранения и восстановления пользовательского интерфейса приложения после его перезапуска или сворачивания, предотвращающий потерю данных и контекста работы пользователя.
State Restoration сохраняет временное состояние UI (позицию скролла, введённые данные в форме), а БД — постоянные пользовательские данные. State Restoration использует системные механизмы (Bundle, NSData) с ограничением по объёму.
Используйте SavedStateHandle в ViewModel из AndroidX Lifecycle. Он автоматически сохраняет данные при сворачивании и восстанавливает при возврате. Для поддержки полного перезапуска используйте SavedStateViewModelFactory.
Установите restorationIdentifier у UIViewController и реализуйте методы encodeRestorableState и decodeRestorableState. Для навигации используйте NSUserActivity с сохранением пути в стеке контроллеров.
Сохраняйте идентификаторы, а не полные данные: ID выбранного элемента, поисковый запрос, позицию скролла, состояние переключателей. Избегайте сохранения больших объектов и изображений.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.