Это перевод первой части из цикла об интеграции ViewModel c Koltin Coroutines, Data Binding и Navigation.
Чтобы более тесно на практике познакомиться с этими компонентами, записывайтесь на продвинутый курс по разработке приложения “Чат-мессенжер”
Об использовании ViewModel
С момента своего появления ViewModel стала одной из самых «базовых» библиотек Android Jetpack. Основываясь на данных бенчмаркинга для разработчиков за 2019 год, более 40% разработчиков Android добавили ViewModels в свои приложения. Если вы не знакомы с ViewModels, причина этого непонятна: ViewModels продвигают лучшую архитектуру, отделяя данные от вашего пользовательского интерфейса, упрощая управление жизненными циклами пользовательского интерфейса и улучшая тестируемость. Для полного объяснения смотрите ViewModels: простой пример и официальную документацию.
Поскольку ViewModels являются настолько фундаментальными, за последние пару лет было проделано много работы, чтобы их было проще использовать и интегрировать с другими библиотеками. В этой и последующих статьях рассмотрим четыре интеграции:
- Сохранение состояния (Saved State) в ViewModel – Данные ViewModel выживают после перезапуска фонового процесса
- NavGraph с ViewModel – интеграция ViewModels и библиотеки навигации
- Использование ViewModels в привязке данных (data-binding) – Простое связывание данных с ViewModels и LiveData
- viewModelScope – интеграция Kotlin Coroutines и ViewModels
Сохранение состояния (Saved State) в ViewModels
Добавлено в lifecycle-viewmodel-savestate: 1.0.0-alpha01
Для Java и Kotlin
Проблема onSaveInstanceState
Когда ViewModel изначально запускался, возникла запутанная проблема, связанная с onSaveInstanceState. Активити и фрагменты могут быть уничтожены тремя способами:
- Вы хотели уйти навсегда: Пользователь уходит или явно закрывает активити – скажем, нажав кнопку «Назад» или запустив некоторый код, вызывающий метод finish(). Активити навсегда исчезла.
- Произошло изменение конфигурации: Пользователь поворачивает устройство или вносит другие изменения в конфигурацию. Активити должна быть немедленно восстановлена.
- Приложение переходит в фоновый режим, и его процесс останавливается. Это происходит, когда на устройстве недостаточно памяти и ему нужно быстро освободить ее. Когда пользователь вернется к вашему приложению, активити нужно будет восстановить.
В ситуациях 2 и 3 вы хотите перестроить активити. ViewModels всегда помогали вам справиться с ситуацией 2, потому что ViewModel не разрушается при изменении конфигурации; но в ситуации 3 ViewModel также уничтожается, поэтому вам действительно нужно сохранять и восстанавливать данные, используя обратный вызов onSaveInstanceState в своей активити. Более подробно об этом здесь.
Saved State Module
Модуль ViewModel Saved State поможет вам справиться с третьей ситуацией: смерть процесса. ViewModel больше не нужно отправлять и получать информацию о состоянии в и из активити. Вместо этого вы теперь можете обрабатывать сохранение и восстановление данных в ViewModel. ViewModel теперь может действительно обрабатывать и хранить все свои собственные данные.
Это делается с помощью SavedStateHandle, который очень похож на Bundle; это map данных ключ-значение. Этот «пакет» SavedStateHandle находится в ViewModel и переживает смерть фонового процесса. Любые данные, которые вы должны были сохранить ранее в onSaveInstanceState, теперь могут быть сохранены в SavedStateHandle. Например, идентификатор пользователя – это то, что вы можете сохранить в SavedStateHandle.
Настройка Saved State Module
Давайте посмотрим, как использовать новый модуль. Обратите внимание, что приведенный ниже код очень похож на этот код из шага 6 Lifecycles Codelab. Этот код на Java, код ниже на Kotlin.
Шаг 1: Добавьте зависимость
SavedStateHandle в настоящее время находится в альфа-версии (это означает, что API может измениться, и мы собираем отзывы), и это отдельная библиотека. Зависимость для добавления:
implementation ‘androidx.lifecycle:lifecycle-viewmodel-savedstate:1.0.0-alpha01’
Обратите внимание: если вы хотите быть в курсе того, какие изменения происходят в библиотеке, загляните на страницу lifecycle release notes.
Шаг 2. Обновите вызов ViewModelProvider
Далее нужно создать тип ViewModel, который имеет SavedStateHandle. В методе onCreate активити или фрагмента обновите ваш вызов ViewModelProvider:
// This ktx requires at least androidx.fragment:fragment-ktx:1.1.0 or // androidx.activity:activity-ktx:1.0.0 val viewModel by viewModels { SavedStateVMFactory(this) } // Or the non-ktx way... val viewModel = ViewModelProvider(this, SavedStateVMFactory(this)) .get(MyViewModel::class.java)
Класс, который создает ViewModel, является фабрикой ViewModel, и есть фабрика ViewModel, которая делает ViewModel с SavedStateHandles под названием SavedStateVMFactory. Созданная ViewModel теперь будет иметь SavedStateHandle, связанную с переданным активити / фрагментом.
Примечание. Предстоящая альфа-версия библиотеки Androidx Activity и фрагментов будет выпущена в июле. В этих выпусках (как отмечено здесь) SavedStateVMFactory станет ViewModelProvider.Factory по умолчанию при создании ViewModel в активити или фрагменте. Это означает, что если вы используете новейшие альфа-версии активити или фрагмента Androidx, вам не нужно добавлять зависимость lifecycle-viewmodel-savestate или явно использовать SavedStateVMFactory. Короче говоря, когда это изменение происходит и если вы используете новые альфа-версии, вы можете пропустить шаги 1 и 2 и просто перейти к шагу 3 ниже.
Шаг 3: Используйте SaveStateHandle во ViewModel
Теперь вы можете использовать SavedStateHandle в вашей ViewModel. Вот пример сохранения идентификатора пользователя в SavedStateHandle:
class MyViewModel(state : SavedStateHandle) : ViewModel() { // Keep the key as a constant companion object { private val USER_KEY = "userId" } private val savedStateHandle = state fun saveCurrentUser(userId: String) { // Sets a new value for the object associated to the key. savedStateHandle.set(USER_KEY, userId) } fun getCurrentUser(): String { // Gets the current value of the user id from the saved state handle return savedStateHandle.get(USER_KEY)?: "" } }
- Construct: MyViewModel принимает SavedStateHandle в качестве параметра конструктора.
- Save: метод saveNewUser показывает пример сохранения данных в SavedStateHandle. Вы сохраняете пару значений ключа USER_KEY, а затем текущий идентификатор пользователя. При обновлении данных в ViewModel они должны быть сохранены в SavedStateHandle.
- Retrieve: saveStateHandle.get (USER_KEY) – пример получения текущего значения, сохраненного в SaveStateHandle.
Теперь, если активити уничтожено из-за поворота экрана или из-за того, что ОС убивает ваш процесс, чтобы освободить память, вы можете быть уверены, что SavedStateHandle будет хранить ваши данные.
Обычно вы будете использовать LiveData в вашей ViewModel. Для этого вы можете использовать метод SavedStateHandle.getLiveData (). Вот пример замены getCurrentUser на LiveData, который позволяет наблюдать:
// getLiveData gets MutableLiveData associated with a key. // When the value associated with the key updates, the MutableLiveData does as well. private val _userId : MutableLiveData<String> = savedStateHandle.getLiveData(USER_KEY) // Only expose a immutable LiveData val userId : LiveData<String> = _userId
Чтобы узнать больше, ознакомьтесь с Шагом 6 Lifecycles Codelab и официальной документацией.
Вопросы о какой-либо из этих функций? Оставьте комментарий! Спасибо за прочтение!
Продолжение здесь