Course Content
-
Сохраняем данные в Room + ViewModel
- Коротко об Android Architecture Components и Room
- Создание проекта и добавление необходимых зависимостей
- Создание Entity
- Создание DAO
- Знакомство с LiveData
- Создание базы данных Room
- Знакомство с патерном Repository (Репозиторий) и создание слоя для доступа к данным
- Создание ViewModel
- Создание ячейки списка для отображения UI
- Создание адаптера и добавление RecyclerView
- Добавление записи в БД используя Room
- Создание Activity
- Подключение к базе данных Room
- Итоги
Создание ViewModel
ViewModel
является частью lifecycle library и предоставляет данные для UI и умеет переживать изменения конфигурации. ViewModel
является посредником между репозиторием и UI. Кроме того, вы можете использовать ViewModel
для обмена данными между фрагментами.
Когда использовать ViewModel?
ViewModel
содержит данные для UI и умеет корректно обрабатывать изменения конфигурации, то есть переживать пересоздание Activity/Fragment. Отдельное от Activity/Fragment хранение данных, который нужно отображать в UI позволяет следовать принципу единственной ответственности (single responsibility principle) Таким образом, пока Activity или Fragment нужны только для создания экрана, ViewModel
в свою очередь занимается наполнением и обработкой данных, отображаемых в UI – элементах. Лучше всего использовать ViewModel
совместно с LiveData
для данных, которые могут изменится после отображения на экране. Использование LiveData
имеет несколько преимуществ:
- Можно подписаться на обновление данных (вместо постоянной проверки на изменения вручную). Тогда UI обновится только в том случае, когда это необходимо, то есть когда изменятся данные.
- Репозиторий (как источник данных) и UI полностью разделены и общаются через
ViewModel
. - Не нужно делать запросы в БД из
ViewModel
(эта логика реализуется в репозитории). Это делает код более тестируемым.
viewModelScope
В Kotlin все корутины запускаются в так называемом
CoroutineScope Скоупы контролиуруют время жизни корутин. Когда вы отменяете задачу в скоупе, то отменяются все корутины запущенные в этом скоупе. Библиотека lifecycle-viewmodel-ktx
являющаяся частью AndroidX имеет расширениеviewModelScope
позволяющее работать со скоупами.
Создание ViewModel
Создадите класс WordViewModel
как показано ниже
// Class extends AndroidViewModel and requires application as a parameter. class WordViewModel(application: Application) : AndroidViewModel(application) { // The ViewModel maintains a reference to the repository to get data. private val repository: WordRepository // LiveData gives us updated words when they change. val allWords: LiveData<List<Word>> init { // Gets reference to WordDao from WordRoomDatabase to construct // the correct WordRepository. val wordsDao = WordRoomDatabase.getDatabase(application).wordDao() repository = WordRepository(wordsDao) allWords = repository.allWords } /** * The implementation of insert() in the database is completely hidden from the UI. * Room ensures that you're not doing any long running operations on * the main thread, blocking the UI, so we don't need to handle changing Dispatchers. * ViewModels have a coroutine scope based on their lifecycle called * viewModelScope which we can use here. */ fun insert(word: Word) = viewModelScope.launch { repository.insert(word) } }
Как обычно, давайте разберём, что здесь есть:
- Класс
WordViewModel
принимаетApplication
в качестве аргумента и наследуется отAndroidViewModel
. val repository
является приватным свойством для хранения ссылки на репозиторий.- Для кэширования списка слов добавим публичное свойство
val allWords: LiveData<List<Word>>
init
блок инициализирует переменнубwordDao
являющейся экземпляромWordDao
изWordRoomDatabase.
- В
init
блоке инициализируется через репозиторий переменная LiveDataallWords
- Метод
insert()
является методом – обёрткой для вызова методаinsert()
в репозитории. Так как работать с БД рекомендуется в отдельном потоке мы используем корутины для вызова метода в отдельном потоке, на случай если вставка элемента затянется, то мы не будем блокировать главный поток, а значит для пользователя работа приложения будет максимально удобной.
В следующих уроках мы создадим UI для отображения данных на экране приложения.