Разработка
Исследуем Now in Android: архитектура, стек технологий, Compose
В этой статье вы познакомитесь с его архитектурой, каждым уровнем и техническим стеком, который используются в проекте Now in Android.
У Google есть относительно новый проект с открытым исходным кодом Now in Android. В этой статье вы познакомитесь с его архитектурой, каждым ее уровнем и техническим стеком, которые используются в проекте.
Прежде чем приступить к делу, мы рекомендуем клонировать Now in Android на локальное устройство и открыть проект в Android Studio.
Если вы соберете Now in Android, результат будет выглядеть так:
Now in Android используется контент, который представляет собой видео с Youtube от команды Google и статьи с Android Developers, поэтому с помощью этого приложения вы можете освоить навыки разработки под Android.
Технический стек
Давайте посмотрим, какие библиотеки используются для создания слоя пользовательского интерфейса в проекте Now in Android:
- Compose: Now in Android на 100% использует Jetpack Compose для создания элементов пользовательского интерфейса. Кроме того, в этом проекте используются соответствующие библиотеки Compose, такие как Activity, Foundation, Material3 и Accompanist.
- Навигация: этот проект использует Navigation Compose для навигации по экранам и Hilt Navigation Compose для внедрения зависимостей.
- WindowManager: Jetpack WindowManager используется для поддержки адаптивных макетов.
- Coil: Coil используется для загрузки изображений для элементов пользовательского интерфейса.
Далее давайте посмотрим, какие библиотеки используются для обработки бизнес-процессов:
- DataStore: хранит данные асинхронно в локальном хранилище данных в виде пар ключ-значение.
- База данных Room: использует локальную базу данных, предоставляя уровень абстракции поверх SQLite, чтобы обеспечить свободный доступ к БД.
- Retrofit: Retrofit — это типобезопасный REST-клиент, предназначенный для использования REST API.
- Сериализация Kotlin: сериализация и десериализация форматов данных, таких как JSON и буферы протоколов, которые можно передавать по сети или хранить в базе данных.
- Корутины Kotlin: предоставляют асинхронные или неблокирующие решения на уровне языка. Корутины полностью использовались в этом проекте для асинхронной обработки задач.
- WorkManager: WorkManager — это рекомендуемое решение для запуска задач в фоновом режиме, которое использовалось для синхронизации локальных данных с сетевыми ресурсами в Now in Android.
Кроме того, приложение Now in Android было создано с использованием приведенных ниже библиотек для улучшения архитектуры и производительности приложения:
- Hilt: Hilt — это библиотека внедрения зависимостей, которая позволяет легко создавать контейнеры внедрения зависимостей и автоматически управлять их жизненными циклами.
- App Startup: App Startup позволяет инициализировать компоненты при запуске приложения.
- Baseline Profiles: Базовые профили позволяют повысить производительность приложения, включив в APK список спецификаций классов и методов, которые могут использоваться Android Runtime.
В этой статье мы рассмотрим некоторые приведенные выше библиотеки и технологические стеки, которые были объяснены на Google I/O 2022 года, а также архитектуру приложения.
Архитектура приложения
Google представил Руководство по архитектуре приложений, в котором представлены передовые методы и рекомендуемые архитектуры для создания надежных и высококачественных приложений.
Now in Android было сделано в соответствии с руководством по архитектуре приложений, так что это бы отличный образец, показывающий, как архитектура работает в реальных проектах.
Теперь давайте изучим архитектуру приложения.
Обзор архитектуры
Общая архитектура состоит из двух уровней: уровня данных и уровня пользовательского интерфейса.
Архитектура следует следующим концепциям:
- Архитектура приложения соответствует однонаправленному потоку данных. Таким образом, уровень пользовательского интерфейса перенаправляет события вниз, а уровень данных перенаправляет результаты вверх.
- Уровень данных предоставляет данные в виде потоков с использованием Kotlin Flow, а элементы пользовательского интерфейса настраивают экраны, наблюдая за потоками.
Теперь давайте рассмотрим каждый слой более подробно.
Слой пользовательского интерфейса
Уровень пользовательского интерфейса состоит из элементов пользовательского интерфейса, таких как кнопки, которые могут взаимодействовать с пользователями, и ViewModel, которая хранит состояния приложения и восстанавливает данные при изменении конфигурации.
Основная роль UI слоя выглядит следующим образом:
- Моделирование состояний пользовательского интерфейса: состояния пользовательского интерфейса моделируются в sealed классах/интерфейсах, которые показывают бизнес-данные в соответствии с единым источником достоверности.
- Преобразование потоков в UI состояния: View модель преобразует потоки данных в состояния пользовательского интерфейса, представляющие бизнес-данные. Элементы пользовательского интерфейса наблюдают за состояниями и отображают их на холсте во всех возможных случаях.
- Обработка взаимодействия с пользователем: передача действий пользователя от элементов пользовательского интерфейса к моделям представлений, а модели представлений выполняют правильную бизнес-логику. События должны проходить от UI элементов к уровню данных, и эта концепция называется однонаправленным потоком данных.
Уровень данных
Уровень данных состоит из репозиториев, которые включают в себя бизнес-логику (такую как сохранение и запрос данных из БД) и запрос удаленных данных из сети. Он реализован как offline-first источник бизнес-логики и следует принципу единого источника достоверности.
Основная роль слоя данных выглядит следующим образом:
- Предоставление данных на уровне UI: уровень данных предоставляет данные в виде потоков, а элементы пользовательского интерфейса настраивают экраны, наблюдая за потоками.
- Гарантия единого источника достоверности: Now in Android гарантируется единый источник достоверной информации, объединяющий данные приложения из нескольких источников данных, таких как локальные базы данных и сети. Репозиторий использует синхронизацию данных для обеспечения этого принципа.
- Синхронизация данных: синхронизация данных между локальной базой данных и сетевыми данными. Работы по синхронизации запускаются при инициализации приложения с помощью App Startup.
Архитектурные потоки
Общий поток архитектуры описывается на рисунке ниже:
Давайте рассмотрим каждый из шагов, один за другим:
- App Startup запускает WorkManager, который выполняет синхронизацию данных.
- WorkManager запускает синхронизацию данных в фоновом потоке. Рабочий процесс запрашивает удаленные источники данных из сети и синхронизирует данные с локальной базой данных приложения.
- Репозиторий преобразует внутреннюю модель данных во внешние данные в виде потоков и предоставляет эти потоки внешним слоям.
- Элементы пользовательского интерфейса настраивают экраны, наблюдая за потоками.
Слой пользовательского интерфейса с Compose
Now in Android 100% использует Jetpack Compose для отрисовки экранов. Jetpack Compose стал стабильным для использования его в продакшене, и Now in Android показывает, как использовать Compose в вашем проекте.
Давайте рассмотрим, как теперь в Android использовать компоненты Jetpack Compose.
Material You
В прошлом году команда дизайнеров Google анонсировала Material You — новый язык дизайна, определяющий темы приложений. Material You реализует динамические цветовые схемы, алгоритмы извлечения, которые позволяют вам получать цветовые схемы из обоев пользовательского устройства.
Добавив приведенную ниже зависимость в свой проект, вы сможете использовать Material Theme, материальные компоненты и динамические цветовые схемы:
Затем вы можете создавать различные динамические цветовые схемы независимо от того, темная системная тема или нет:
Для получения дополнительной информации о Material You ознакомьтесь со статьей “Использование Material You для Jetpack Compose”.
В результате вы увидите разные цвета компонентов, как показано на картинке ниже:
Темы
Темы — одна из важнейших частей современной разработки для Android, и применять согласованные темы в каждом элементе пользовательского интерфейса на основе XML непросто. Однако с помощью Jetpack Compose определение тем и их применение к элементам пользовательского интерфейса упрощается, а большинство атрибутов можно настраивать.
Now in Android использует Material Theme для определения цветовых схем и их настройки. Как видно из приведенного ниже примера, вы можете определить свои цветовые схемы с помощью методов lightColorSceme и darkColorSceme:
Кроме того, Now в Android использует методы dynamicLightColorScheme и dynamicDarkColorScheme для получения динамических цветовых схем, генерируемых из обоев пользовательского устройства.
Наконец, composable функция NiaTheme выглядит следующим образом:
Как вы можете видеть в приведенном выше примере, вы можете применять собственные или динамические цветовые схемы и легко переключаться между ними в определенных ситуациях.
Большие экраны
В последнее время поддержка больших экранов является одной из важных частей современной Android-разработки. Теперь в Android поддерживается адаптивная раскладка с помощью Jetpack WindowManager.
Во-первых, вам нужно добавить следующие зависимости в файл build.gradle:
Затем вы можете рассчитать размера окна на основе размера пользовательского устройства с помощью метода calculateWindowSizeClass:
Класс WindowSizeClass предлагает три точки останова: Compact, Medium и Expanded. Как вы можете видеть во внутреннем коде ниже, эти три точки останова рассчитываются в соответствии со спецификациями руководства по материальному дизайну:
После вычисления WindowSizeClass, Now в Android рисует различные элементы пользовательского интерфейса с помощью WindowSizeClass:
В приведенном выше примере на главном экране отображается нижняя панель, если WindowSizeClass имеет значение Compact, и боковая панель, если WindowSizeClass имеет значение Medium или Expanded.
В результате вы увидите разные экраны, соответствующие ширине пользовательского устройства, как на изображении ниже:
Дополнительные сведения об адаптивных макетах вы можете прочитать в статье “Изучение Jetpack WindowManager для складных устройств”.
Производительность приложения
Устройства Android используют очень ограниченные ресурсы, поэтому повышение производительности приложений — самая важная часть Android-разработки, обеспечивающая удобство работы пользователей.
Итак, давайте рассмотрим, как мы можем улучшить производительность приложения с помощью Jetpack Compose.
Remember
Jetpack Compose использует remember API для хранения объектов в памяти. API сохраняет вычисленное значение на этапах композиции и восстанавливает сохраненное значение во время рекомпозиции.
Давайте посмотрим пример. Приведенный ниже код будет сортировать все контакты всякий раз, когда происходит перекомпоновка:
Сортировка списка требует больших затрат, если список контактов включает много элементов, и это может снизить производительность приложения. Таким образом, вы можете использовать remember для запоминания значений, которые требуют больших затрат, например, сортировки.
Как показано в приведенном выше примере, вы можете сохранить отсортированное значение в памяти с помощью remember API. Вычисление не будет выполнено, когда произойдет перекомпоновка и повторное использование отсортированного значения.
Кроме того, код использует список контактов и компаратор в качестве ключей при запоминании, поэтому сортировка будет выполняться повторно, только если значения ключа будут изменены.
Ленивые списки
Прежде чем исследовать ленивые списки, давайте посмотрим, в чем разница между Column и LazyColumn в Jetpack Compose.
Они выглядят очень похожими, и Column также может отображать список элементов с оператором for. Но Column отображает все элементы в скоупе независимо от того, виден элемент или нет, и это может снизить производительность приложения, если в списке много элементов.
С другой стороны, LazyColumn принял концепцию, аналогичную RecyclerView, и LazyColumn отображает только видимые элементы на экране. Таким образом, вы можете повысить производительность приложения, если будете использовать LazyColumn вместо Column, когда элементов много.
Далее предположим, что положение элемента изменилось. Сейчас LazyColumn не может различать отдельные элементы в списке, LazyColumn будет перекомпонован для всего списка. Таким образом, при изменении позиции элемента возникает провал в производительности.
Вы можете улучшить производительность LazyColumn, указав ключевой параметр, представляющий уникальный идентификатор для каждого элемента, как показано ниже:
Предоставляя ключевой параметр, LazyColumn может различать отдельные элементы всякий раз, когда положение элемента изменяется, и не будет производить рекомпозицию для всего списка.
Если вы хотите узнать больше о производительности Jetpack Compose, ознакомьтесь с “Производительность Compose”.
Базовые профили
Базовые профили (Baseline Profiles) — это спецификации классов и методов, включенных в файлы APK и AAB, которые могут использоваться средой выполнения Android. Спецификации могут быть предварительно скомпилированы и предварительно загружены в память при установке или обновлении приложения.
Android Runtime выполняет компиляцию спецификаций с опережением времени (AOT), что позволяет приложениям оптимизировать запуск, уменьшить зависания пользовательского интерфейса и повысить производительность.
В частности, базовые профили значительно повышают производительность приложений для проектов с Jetpack Compose. Потому что Jetpack Compose — это библиотека, а значит, она не участвует в совместном использовании системных ресурсов с ОС Android.
Чтобы сгенерировать спецификацию метода с помощью базовых профилей, добавьте приведенную ниже зависимость в файл build.gradle:
Now in Android использует класс BaselineProfileGenerator для создания профилей:
В результате генератор профилей сгенерирует приведенные ниже спецификации в текстовом файле, который будет использоваться для предварительной компиляции средой выполнения Android:
Для получения дополнительной информации ознакомьтесь с базовыми профилями.
Итого
В этой статье мы разобрали Now in Android и рассмотрели основные аспекты современной Android-разработки, включая архитектуру приложений, библиотеки Jetpack, слой пользовательского интерфейса с Compose и производительность приложения.
Вы можете найти автора этой статьи в Twitter @github_skydoves или в GitHub, если у вас есть какие-либо вопросы или отзывы.
И как всегда — удачного программирования!