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 поділяється на дві фази: збереження та відновлення. На фазі збереження система викликає відповідні методи життєвого циклу, в яких додаток повинен серіалізувати поточний стан 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 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також