Помню, как однажды я провела целую вечность, заполняя форму и вводя тонну информации и адрес, чтобы сделать заказ. Но потом я случайно повернула телефон, и всё пропало. После этого я больше никогда не заходила в это приложение. Сейчас этой компании не существует. А вот если бы они задумались о смене конфигурации и сделали бы всё правильно с самого начала, может быть, они были бы популярными до сих пор. :)
Когда происходит смена конфигурации (например, поворот экрана), система уничтожает активити и создает новую. Из-за этого у разработчиков всегда много проблем, потому что данные теряются и надо как-то их сохранять/восстанавливать.
ViewModel очень сильно выручает нас тут. Она спроектирована таким образом, что может переживать смену конфигурации. Краткое описание как это работает:
- ViewModelStore: у каждой активити есть ViewModelStore (https://github.com/androidx/androidx/blob/androidx-main/lifecycle/lifecycle-viewmodel/src/androidMain/kotlin/androidx/lifecycle/ViewModelStore.kt). Подробнее про это я писала здесь: https://dzen.ru/a/ZUZ6NobTliU1wfgd. Когда активити уничтожается при смене конфигурации, ее ViewModelStore не уничтожается вместе с ней. Вместо этого ViewModelStore сохраняется через механизм, который называется "retaining".
- Retaining: когда активити уничтожается из-за смены конфигурации, система знает об этом и удерживает ViewModelStore (звучит как магия, правда?). После того как новый экземпляр активити создается, он получает тот же ViewModelStore, что и предыдущая активити.
- ViewModelProvider: когда мы создаем ViewModel через ViewModelProvider, он проверяет, существует ли уже ViewModel в ViewModelStore. Если да, то он возвращает существующий экземпляр вместо создания нового.
Это всё означает, что ViewModel сохраняется в памяти, даже когда активити уничтожается и создается заново, что позволяет сохранять данные.
(Важно!) Мы не касаемся сценария, когда активити уничтожается окончательно, например, когда пользователь нажимает кнопку "Назад". В таких случаях ViewModel уничтожается окончательно и будет вызван метод onCleared().
Звучит всё просто. Но что ещё за retaining? Давайте разберемся.
Перед уничтожением активити из-за смены конфигурации вызывается метод onRetainNonConfigurationInstance (https://developer.android.com/reference/android/app/Activity#onRetainNonConfigurationInstance()). Этот метод вызывается автоматически системой внутри жизненного цикла активити и помогает сохранять данные. Разработчики его не трогают и ничего там не пишут. За нас уже всё сделали.
Система использует возвращаемое значение этого метода и сохраняет его на время пока активити пересоздаётся. Затем, при создании новой активити, это сохраненное значение можно получить с помощью метода getLastNonConfigurationInstance (https://developer.android.com/reference/android/app/Activity#getLastNonConfigurationInstance()).
Вот и вся магия. Теперь, когда ViewModelProvider запросит ViewModelStore, то он получит сохраненный экземпляр и вернет соответствующие ViewModel, которые там хранились.
Подробнее про методы:
onRetainNonConfigurationInstance:
- Это метод в активити, который используется для сохранения данных при смене конфигурации, например, при повороте экрана.
- Метод вызывается перед уничтожением активити и её последующим созданием из-за смены конфигурации.
- Метод возвращает объект, представляющий данные, которые мы хотим сохранить. Это может быть любой объект или структура данных по нашему усмотрению. Что хотим, то и сохраняем (котика, уши, лапы, хвост, строку).
- Возвращенный объект будет передан новому экземпляру активити после её пересоздания.
Пример реализации из документации:
Тут видно, что в этом методе сохраняется ViewModelStore, который как раз хранит все наши ViewModel.
getLastNonConfigurationInstance:
- Используется для получения объекта, который был возвращен в методе onRetainNonConfigurationInstance.
- Его можно вызвать самостоятельно. Но обычно внутри метода onCreate пересозданной активити.
- Именно этот метод используется для ViewModel, чтобы получить сохраненный ViewModelStore.
Пример реализации из документации:
Тут метод совсем простой. Возвращаем сохраненную конфигурацию если она есть. Если нет, то возвращаем null.
Дубль статей в телеграмме — https://t.me/android_junior
Мои заметки в телеграмме — https://t.me/android_junior_notes
P.S. сделано с помощью документации, ChatGPT и Midjourney. :)