Android Architecture Components. Часть 1. Введение
На Google I/O 2017, было представлено набор библиотек под названием Android Architecture Components. В нескольких словах — это ряд вспомогательных библиотек, которые призваны помочь с такими вещами как, проектирование, тестирование и сопровождение приложений. То, что команда разработки Android начала акцентировать внимание на архитектуре не может не радовать, поскольку проблема является действительно актуальной. Ведь изначально не было предоставлено никаких требований или гайдлайнов по проектированию, и разработчику приходилось отталкиваться от своего предыдущего опыта. Что, в свою очередь, вызывало сложности в сопровождении проекта, а также сомнительные решения для специфических для ОС ситуаций. По факту это не первые шаги в этом направлении. Ранее уже Google представил репозиторий android-architecture с примерами применения разных архитектурных концептов. Надеемся, что развитие будет дальше и может на следующем Google I/O мы сможем увидеть полноценный фреймворк.
В целом Android Architecture Components можно разделить на четыре блока: Lifecycles, LiveData, ViewModel и Room Persistence.
Компонент Lifecycle – призван упростить работу с жизненным циклом. Выделены основные понятия такие как LifecycleOwner и LifecycleObserver.
LifecycleOwner – это интерфейс с одним методом getLifecycle(), который возвращает состояние жизненного цикла. Являет собой абстракцию владельца жизненного цикла (Activity, Fragment). Для упрощения добавлены классы LifecycleActivity и LifecycleFragment.
LifecycleObserver – интерфейс, обозначает слушателя жизненного цикла owner-а. Не имеет методов, завязан на OnLifecycleEvent, который в свою очередь разрешает отслеживать жизненный цикл.
Что это нам дает?
Назначение этого компонента – избавить разработчика от написания рутинного кода и сделать его более читаемым. Довольно частая ситуация, когда в нашем приложении работает ряд процессов, которые зависят от этапа жизненного цикла. Будь-то воспроизведение медиа, локация, связь с сервисом и т.д. Как итог нам приходится вручную отслеживать состояние и уведомлять о нём наш процесс. Что неудобно по двум причинам, захламление основного класса (Activity или Fragment) и снижение модульности, ведь нам нужно позаботиться про поддержку передачи состояния. С помощью же этого компонента мы можем переложить всю ответственность на наш компонент и все что для этого нужно это объявить интересующий наш класс как observer и передать ему в onCreate() методе ссылку на owner. В общем это выглядит так:
Наш обсервер абсолютно осведомлен о состоянии и может самостоятельно обрабатывать его изменение.
Компонент LiveData – являет собой holder класс для хранения объекта, а также разрешает подписаться к нему. LiveData знает про жизненный цикл и разрешает от него абстрагироваться.
Для имплементации компонента нам нужно расширить класс LiveData. Для работы нам нужно знать всего три метода из этого класса.
onActive() – этот метод вызывается когда у нашего экземпляра есть активный(-ые) обсервер. В нем мы должны инициировать интересующий нас сервис или операцию.
onInactive() – вызывается когда у LiveData нет активных слушателей. Соответственно нужно остановить наш сервис или операцию.
setValue() – вызываем если изменились данные и LiveData информирует об этом слушателей.
Если вы обратили внимание, то мы реализовали наш класс как Singleton. Это дает нам возможность использовать LiveData в других Activity, Fragment и т.д без переинициализации, если это нам не нужно.
Для того чтоб подписать слушателя, тоже никаких проблем нет. Все что нужно это вызвать метод observe у нашего экземпляра LiveData, передать в него LifeCycleOwner и реализацию интерфейса Observer. Интерфейс Observer имеет всего один метод onChanged(T t), с помощью него LiveData будет информировать слушателей об изменении в данных(вызов метода setValue(T t) в LiveData).
Что это нам дает?
Плюсов действительно много, начиная от защиты от memory leaks(Observer связан со своим Lifecycle и автоматически отписывается в случае, когда его Lifecycle уничтожен), защита от остановленной Activity(если, Lifecycle неактивен(stopped), то и нотификации на Observer не будут отправляться). С функциональных особенностей, это единый доступ к данным(с помощью singleton) и сбережение наших данных(Для таких операций как пересоздание активити, фрагмента). В целом же, назначение все то же, избавить разработчика от рутинной работы связанной с жизненным циклом.
Компонент ViewModel — спроектирован для хранения и управления данными которые связанные с представлением.
Задача же данного компонента, помочь разработчику абстрагировать данные и предоставить их хранение между такими операциями как пересоздание Activity. Если же нам необходимо сохранить небольшой набор данных, таких как item в RadioButtonGroup или же введенный данные, нам отлично подходит Bundle в onSaveInstanceState(). Но если это большой список к примеру: пользователей, товаров, каталог чего-нибудь нам приходилось заново доставать этот список. Вот в этом случае ViewModel является нашим основным помощником. Особенностью данного компонента является то что он привязывается к Activity и автоматически сохраняет свое состояние во время таких операций как onCofigurationChange().
Класс ViewModel, являет собой абстрактный класс, но не имеет абстрактных методов. Для реализации нашего класса нам нужно лишь наследоваться от ViewModel и описать данные которые мы хотим хранить и методы для их получения.
И это все, наш холдер для userList готов. Для того чтоб использовать наш холдер необходимо в методе onCreate(..) активити вызвать instance нашей модели:
С помощью ViewModelProviders, мы берем instance нашей модели. A c помощью if конструкции смотрим есть ли у нас уже данные в нашей модели или еще нет.
Что это нам дает?
Также как и предыдущие компоненты, этот помогает нам справится с особенностями и связанными с ними проблемами жизненного цикла Android. В этом случае, это отделение нашей модели представления данных от Activity и обеспечение безопасного механизма их хранения. Также при использовании совместно с LiveData не составляет проблем реализовать асинхронные запросы.
Компонент Room Persistence — Предлагает уровень абстракции над SQLite, предлагая более простой и продвинутый способ управления.
В целом же мы получили дефолтную ORM, этот компонент можно разделить на три части: Entity, DAO (Data Access Object), Database.
Entity — объектное представление таблицы. С помощью аннотаций можно легко и без лишнего кода описать наши поля.
Для создания нашей Entity нам нужно создать класс POJO (Plain Old Java Object). Пометить класс аннотацией Entity.
@PrimaryKey — Для обозначения ключа. @ColumnInfo — для связи поля в таблице. Создавать методы get и set не обязательно, но тогда нужно предоставить доступ к переменным с помощью модификатора public.
Установление связей объявляется также в теле аннотации Entity: Entity(foreignKeys = @ForeignKey(entity = Other.class, parentColumns = «id», childColumns = «author_id»))
DAO — Интерфейс который описывает методы доступа к БД.
Для реализации создаем интерфейс который помечаем аннотацией DAO и объявляем наши методы. Основные аннотации для методов это Insert Update Delete Query, в комментариях не нуждаются.
В обычном состоянии попытка получить доступ к БД с основного потока закончиться Exception. Если вы все же уверены в своих действиях, то можно воспользоваться методом allowMainThreadQueries(). Для асинхронного доступа рекомендовано использовать LiveData или RxJava.
Database — используется для создания Database Holder и является точкой доступа к соединению с БД.
Для создания нашего класса нужно наследоваться от RoomDatabase и использовать аннотацию Database, которой передаем параметры такие как используемые entity и версию базы. В теле описываем абстрактные методы доступа к нашим DAO.
Для создания instance для нашей БД используем код:
Для хранения db рекомендуют использовать singleton.
Что это нам дает?
Упрощение работы с базой данных, отпадает потребность в использовании сторонних ORM.
Кроме описанных выше плюшек NestedObject, параметры в запросах, коллекции аргументов, TypeConverter, database migration и т.д. Эти темы не входят в скоуп данного материала и будут рассмотрены позже.
К завершению материала хочу добавить еще несколько слов об архитектуре. С представлением Android Architecture Components была предложена архитектура решений, которая для большинства разработчиков уже и так привычна в той или иной форме. Суть заключается в том, что мы разбиваем архитектуру на 3 основных слоя: View (Activity/Fragment), который общается с ViewModel, а ViewModel работает непосредственно уже с Repository. Для наглядности преведу картинку с developer.android.com.
Выглядит абсолютно просто, а как на самом деле мы рассмотрим в следующих статьях.
Где сначала разберем более подробно каждый компонент и в конце реализуем приложение, как говорится с базой данных и… коннектом к сервису.
Источник
Architecture Components
Android Architecture Components — это набор решений от Google, которые помогут вам в разработке приложений.
Я разработал бесплатный курс по этой теме. Он охватывает следующие подтемы:
1. Activity и Fragment Lifecycle
Architecture Components предоставляют несколько механизмов, сочетание которых, позволит вам удобно обрабатывать повороты экрана.
Lifecycle — отслеживает текущий статус Activity и может уведомлять об этом своих подписчиков
LiveData — получает и хранит данные, может отправлять их своим подписчикам
ViewModel — поможет сохранить живыми необходимые для вас объекты при повороте экрана
Полезные ссылки по теме:
2. База данных
Room — удобная обертка для работы с базой данных.
3. Постраничная загрузка данных
Paging Library — библиотека для постраничной загрузки данных из базы данных, с сервера или любого другого источника.
4. Data Binding
Избавит вас от написания кучи кода по работе с View. Его удобно использовать с ViewModel.
5. Navigation Architecture Component
Новый компонент для навигации по экранам приложения.
6. WorkManager
Новый механизм выполнения фоновых задач
7. Примеры использования
Обсуждать эти темы можно в нашем Telegram чате.
После теоретических уроков я планирую поразбирать интересные примеры, в которых используются эти компоненты.
Список уроков:
В этом уроке рассмотрим возможности Lifecycle. Как подписаться на его события. Как узнать текущее состояние Activity.
В этом уроке рассмотрим основные возможности LiveData. Как подписаться на его данные. Как помещать в него данные. Как он взаимодействует со своими подписчиками.
В прошлом уроке мы разобрались, как отправлять и получать данные в LiveData. В этом уроке рассмотрим несколько дополнительных возможностей. Как преобразовать тип данных с помощью map. Как создать свой LiveData. Как объединить несколько LiveData в один с помощью MediatorLiveData.
В этом уроке рассмотрим, как использовать ViewModel. Как сохранять данные при повороте экрана. Как передать Context в ViewModel. Как передать свои данные в конструктор модели с помощью фабрики. Как передать данные между фрагментами. Что использовать: ViewModel или onSavedInstanceState.
Библиотека Room предоставляет нам удобную обертку для работы с базой данных SQLite. В этом уроке рассмотрим основы. Как подключить к проекту. Как получать, вставлять, обновлять и удалять данные.
В этом уроке более подробно рассмотрим возможности Entity. Как задать имя таблицы. Как задать имя или тип поля. Как создать составной или внешний ключ. Как создать индекс. Как использовать вложенные объекты.
В этом уроке рассмотрим подробнее аннотации Insert, Update и Delete. А также узнаем, как использовать транзакции в Room.
В этом уроке поговорим подробнее про Query. В каком виде мы можем получать данные: List, массив, Cursor, LiveData. Как передавать параметры. Как получать только некоторые поля. Как с помощью Query выполнять update и delete запросы в Room.
В этом уроке рассмотрим возможность совместного использования RxJava и Room. Как получать данные в Flowable, Single и Maybe.
В этом уроке рассмотрим, как получать данные из нескольких таблиц. А также разберемся, как использовать аннотацию Relation.
В этом уроке рассмотрим, как использовать конвертеры типов данных, чтобы Room мог сохранять не только поля-примитивы.
В этом уроке рассмотрим, как выполняется миграция версий базы данных в Room
В этом уроке рассмотрим, как тестировать Room. Напишем несколько тестов для Dao и протестируем миграцию.
В этом уроке начнем знакомство с Paging Library. Рассмотрим общую схему работы связки PagedList и DataSource.
В этом уроке рассмотрим, какие параметры мы можем задать для PagedList. Подробно разберем, какие значения необходимо передавать в callback.onResult в DataSource. Научимся использовать режим Placeholders.
В этом уроке обсудим, в каких потоках выполняется код загрузки данных. Разберем возможности LivePagedListBuilder. Узнаем, как использовать Paging Library с Room.
В этом уроке рассмотрим, чем отличаются существующие виды DataSource: PositionalDataSource, PageKeyedDataSource, ItemKeyedDataSource
В этом уроке знакомимся с Data Binding.
В этом уроке рассматриваем возможность написания кода в layout и получаем View от биндинга.
В этом уроке рассмотрим как обрабатывать события View.
В этом уроке разберем, как настроить автоматическую передачу данных в View и обратно.
В этом уроке разберем, как можно расширить возможности биндинга с помощью Binding Adapter и Binding Conversion.
В этом уроке рассмотрим примеры использование Android Data Binding с include, ViewStub и RecyclerView
В этом уроке рассмотрим простой пример использования Navigation Architecture Component.
В этом уроке рассмотрим как передавать данные при навигации.
В этом уроке разбираемся, как задавать параметры при навигации.
В этом уроке рассмотрим интеграцию Navigation Component c Overflow Menu, Navigation Drawer и BottomNavigationView.
В этом уроке рассмотрим вложенный граф, global action и deep link.
В этом уроке знакомимся с WorkManager.
В этом уроке задаем критери для запуска задачи.
В этом уроке рассматриваем, как запускать задачи в определенном порядке
В этом уроке рассмотрим как передать данные в задачу и как получить результат
В этом уроке я распишу, что будет в практических уроках.
В этом уроке разбираем экран Tasks (список задач) приложения TodoApp
В этом уроке разбираем экран TaskDetail (просмотр задачи) приложения TodoApp
Курс бесплатен. Если у вас есть желание выразить благодарность, то используйте Яндекс-форму или PayPal. Спасибо!
Источник