При разработке мы часто сталкиваемся с проблемой смены конфигурации (например, когда поворачивается экран и данные теряются). Это может расстроить пользователя, и он поставит приложению плохой отзыв. Разработчик разочаруется в себе, что приведёт к выгоранию, депрессии и в итоге он уезжает жить в деревню, бросая всё. Поговорим о том, как можно избежать всего этого.
Небольшое введение в ViewModel
ViewModel является частью библиотеки Android Jetpack. Она предназначена для хранения и управления данными, связанными с UI, в соответствии с жизненным циклом активити или фрагмента. По сути, она работает как мост между репозиторием данных и пользовательским интерфейсом.
ViewModel сохраняет своё состояние и не уничтожается при смене конфигурации. Это происходит благодаря тому, что объекты ViewModel живут в специальном хранилище (ViewModelStore), которое не уничтожается при смене конфигурации. Вместо этого, при пересоздании активити, новый экземпляр активити может получить доступ к уже существующему ViewModel и продолжить работу с текущим состоянием данных.
Вот так выглядит простая ViewModel: https://github.com/Ladgertha/Asteroid-Radar/blob/master/app/src/main/java/ru/ladgertha/asteroidradar/main/MainViewModel.kt
Основные компоненты
- ViewModelStore — это такой контейнер, который хранит ViewModels (там внутри просто mutableMapOf<String, ViewModel>(), где ключами являются идентификаторы ViewModel, а значениями — сами ViewModel).
Каждая активити и каждый фрагмент имеют свой ViewModelStore, который живёт в течение всего жизненного цикла соответствующего компонента. При смене конфигурации (например, при повороте экрана), активити будет уничтожена и пересоздана, но её ViewModelStore сохранится. Можете посмотреть сам класс и увидеть, что он достаточно простой: https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/ViewModelStore.kt - ViewModelStoreOwner — это интерфейс, который обеспечивает доступ к ViewModelStore. Если посмотрите исходники, то он состоит просто из val viewModelStore: ViewModelStore. https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/ViewModelStoreOwner.kt
- ViewModelProvider — этот класс ответственен за создание и получение ViewModels (чуть ниже будет про него): https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/ViewModelProvider.kt
- ViewModelProvider.Factory — это интерфейс, который даёт нам метод для создания ViewModels. По умолчанию используется NewInstanceFactory, если мы не сделаем собственную реализацию. Кастомные Factory позволяют создавать ViewModel с параметрами конструктора, что дает дополнительную гибкость: https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/ViewModelProvider.kt;l=70
Жизненный цикл ViewModel
Когда мы запрашиваем ViewModel через ViewModelProvider, происходит следующее:
- ViewModelProvider проверяет, существует ли уже созданная ViewModel в ViewModelStore для текущей активити или фрагмента.
- Если ViewModel найдена, она возвращается для использования. Если не найдена, то ViewModelProvider.Factory используется для создания новой ViewModel и она потом сохраняется в ViewModelStore.
- С созданной ViewModel мы можем взаимодействовать, и она будет жить до тех пор, пока живёт активити или фрагмент.
- Если активити/фрагмент уничтожается навсегда (то есть пользователь закрыл её, либо был вызван метод finish(), либо фрагмент удалён), то ViewModelStore очищается, и все хранящиеся в нем ViewModel объекты удаляются. Также вызывается onCleared() для каждой ViewModel, позволяя очистить ресурсы, которые могут в противном случае привести к утечке памяти.
Самое интересное: по умолчанию, если активити пересоздается, все ViewModel, связанные с этой активити, сохраняются, чтобы они могли быть переданы новому экземпляру активити. Только при окончательном завершении активити ViewModel удаляется и вызывается метод onCleared().
Такое поведение делает ViewModel идеальной для обработки данных, связанных с UI, которые должны сохраняться в течение всего жизненного цикла активити или фрагмента.
Дубль статей в телеграмме — https://t.me/android_junior
Мои заметки в телеграмме — https://t.me/android_junior_notes
P.S. сделано с помощью ChatGPT и Midjourney. :)