- Jetpack Compose — как легко построить UI на Android
- Преимущества Jetpack Compose
- Подключение к проекту
- Первое впечатление от Android Jetpack Compose
- Что такое Android Jetpack Compose?
- 1. Независимость от релизов Android
- 2. Весь API на Kotlin
- 3. Composable = Композитный: использование композиции вместо наследования
- 4. Однонаправленный поток данных
- 5. Улучшение отладки
- Хватит слов, покажите код
- 1. FrameLayout vs Wrap + Padding + Background
- 2. Вертикальный LinearLayout vs Column
- 2a. Отступы
- 2b. Интервалы
- 2c. Горизонтальный LinearLayout vs Row
- 2d. Gravity vs Alignment
- 2d. Замечание
- 3.Стили и темы
- Что посмотреть/почитать
- Выводы
- Погружение в Jetpack Compose
- Пробуем новый UI-фреймворк для Android-приложений
- Jetpack Compose спешит на помощь
- Простое приложение с Compose: Hello World
- Введение состояния
- Пользовательские модели состояний
- Больше никаких view
- Все элементы являются виджетами
- Соединение кода с пользовательским интерфейсом
- Совместимость с вашими Android-приложениями
- Заключение
Jetpack Compose — как легко построить UI на Android
В июле этого года вместе с Android Studio Arctic Fox вышла одна из долгожданных библиотек — Jetpack Compose. Она позволяет создавать пользовательский интерфейс в декларативном стиле и обещает быть революцией в построении UI.
Разбираемся, так ли это на самом деле, какие у библиотеки преимущества и недостатки. Подробности — в статье.
Преимущества Jetpack Compose
Jetpack Compose — это набор инструментов для разработки UI в Android-приложении. Он призван ускорить и упростить разработку пользовательского интерфейса, избавить от лишнего кода и соединить модель реактивного программирования с лаконичностью Kotlin.
Сразу с места в карьер — какие есть преимущества у библиотеки:
1. Меньше кода. Jetpack Compose позволяет писать меньше кода, а значит разработчик может больше фокусироваться на проблеме, с меньшим количеством тестов и дебага, а значит и багов.
2. Интуитивно понятный. Compose использует декларативный API — разработчику нужно лишь сказать, что сделать, а все остальное ляжет на плечи библиотеки.
3. Удобство внедрения. Compose совместим с любым существующим кодом. Например, можно вызвать Compose-код из вьюх (view) и, наоборот, вьюхи из Compose. Многие библиотеки вроде Jetpack Navigation, ViewModel и Coroutines уже адаптированы под Compose, что позволяет сравнительно быстро внедрить его в свой код. Кроме того, Android Studio Arctic Fox поддерживает превью создаваемых вьюх.
4. Имеет обширный инструментарий. Jetpack Compose позволяет создавать красивые приложения с прямым доступом к Android Platform API и build-in поддержкой Material Design, тёмной темы, анимаций и других крутых штук.
Далее пройдёмся по основным аспектам библиотеки и посмотрим, как сильно повышается производительность приложения.
Подключение к проекту
Чтобы подключить Jetpack Compose к проекту, необходимо указать некоторые строки кода в своем build.gradle.
В рутовом объявим переменную с версией Compose:
Здесь мы указываем, что в проекте будем использовать Jetpack Compose и объявляем необходимые зависимости (подробнее про зависимости можно почитать в официальном гайде).
Дальше всё просто. В активити (activity) объявлем Composable-функцию, строим иерархию вьюх с указанием необходимых атрибутов и смотрим результат.
Пройдемся по коду. Я написал две реализации вёрсток различной сложности:
1. Простая реализация
Добавляет TextView в вёрстку с текстом с конкатенацией Hello и аргумента, переданного в Greeting.
Важно отметить, что имена Composable-функций начинаются с заглавной буквы. Это соглашение по наименованию функций, поэтому если писать со строчной, то студия будет подсвечивать неверный нейминг.
2. Более сложная реализация
Этот вариант представляет собой скролящийся экран, который содержит изображение, текст и кнопку. Рассмотрим некоторые особенности:
Необходимо объявить Scroll State. Только не обычный, а тот, который позволяет сохранять состояние скролла сквозь рекомпозицию — rememberScrollState().
Column представляет собой ViewGroup с вертикальным расположением элементов.
Modifier позволяет управлять атрибутами, добавлять декорации и поведение к вьюхам.
Остальное интуитивно понятно. И это как раз одна из ключевых особенностей Jetpack Compose — даже если вы не использовали библиотеку ранее, то всё равно с ней разберётесь.
Добавить вьюхи в активити можно через extension setContent <>, например:
В общем-то, создание UI выглядит действительно просто. Теперь определим, насколько сильно оптимизируется приложение и как быстро пользователь увидит окончательный экран.
Для тестирования воспользуемся библиотекой Jetpack Benchmark, о которой, кстати, тоже рассказывали в отдельной статье. Код теста выглядит так:
Протестируем три версии установки вьюхи в активити:
При передаче ресурса в setContentView.
При передаче вьюхи в setContentView.
Итоги тестирования можно посмотреть в таблице: левый столбец — название теста, правый — время на выполнение:
Источник
Первое впечатление от Android Jetpack Compose
После того, как на Google IO 2019 я увидел доклад про Android Jetpack Compose, захотелось сразу же его попробовать. Тем более, что подход, реализованный в нём, очень напомнил Flutter, которым я интересовался ранее.
Сама библиотека Compose находится в пре-альфа стадии, поэтому доступно не так много документации и статей про нее. Далее я буду полагаться на несколько ресурсов, которые мне удалось найти, плюс открытые исходники библиотеки.
Вот эти ресурсы:
Что такое Android Jetpack Compose?
Раньше весь UI в Android был основан на классе View. Так повелось с первых дней Android. И в связи с этим накопилось множество легаси и архитектурных недостатков, которые могли бы быть улучшены. Но сделать это достаточно сложно, не сломав весь код, написанный на их основе.
За последние годы появилось множество новых концептов в мире клиентских приложений (включая веяния Frontend-а), поэтому команда Google пошла радикальным путём и переписала весь UI-уровень в Android с нуля. Так и появилась библиотека Android Jetpack Compose, включающая в себя концептуальные приёмы из React, Litho, Vue, Flutter и многих других.
Давайте пройдемся по некоторым особенностям существующего UI и сравним его с Compose.
1. Независимость от релизов Android
Существующий UI тесно связан с платформой. Когда появились первые компоненты Material Design, они работали только с Android 5 (API21) и выше. Для работы на старых версиях системы необходимо использовать Support Library.
Compose же входит в состав Jetpack, что делает его независимым от версий системы и возможным для использования даже в старых версиях Android (как минимум с API21).
2. Весь API на Kotlin
Раньше приходилось иметь дело с разными файлами, чтобы сделать UI. Мы описывали разметку в xml, а затем использовали Java/Kotlin код, чтобы заставить ее работать. Затем мы снова возвращались в другие xml-файлы для того чтобы задать темы, анимацию, навигацию,… И даже пытались писать код в xml (Data Binding).
Использование Kotlin позволяет писать UI в декларативном стиле прямо в коде вместо xml.
3. Composable = Композитный: использование композиции вместо наследования
Создание кастомных элементов UI может быть довольно громоздким. Нам необходимо унаследоваться от View или его потомка и позаботиться о многих важных свойствах перед тем, как он правильно заведется. Например, класс TextView содержит около 30 тысяч строк Java-кода. Это связано с тем, что он содержит множество лишней логики внутри себя, которую наследуют элементы-потомки.
Compose подошел с другой стороны, заменяя наследование композицией.
Padding как нельзя лучше подойдет для иллюстрации того, о чем речь:
В существующем UI для того, чтобы отрисовать TextView c отступами в 30dp :
нам нужно написать следующий код:
Это означает, что где-то внутри TextView.java или его суперклассов содержится логика, которая знает, как посчитать и отрисовать отступы.
Давайте посмотрим, как можно сделать то же самое в Compose:
Изменения
TextView стал просто Text() . Свойство android:padding превратилось в Padding , который оборачивает Text .
Преимущества
Таким образом, Text отвечает только за отрисовку непосредственно текста. Он не знает про то, как считать отступы. С другой стороны, Padding отвечает только за отступы и ничего больше. Он может быть использован вокруг любого другого элемента.
4. Однонаправленный поток данных
Однонаправленный поток данных является важным концептом, если мы говорим, например, про управление состоянием CheckBox в существующей системе UI. Когда пользователь тапает на CheckBox , его состояние становится checked = true : класс обновляет состояние View и вызывает callback из кода, который следит за изменением состояния.
Затем в самом коде, например, во ViewModel , вам нужно обновить соответствующую переменную state . Теперь у вас есть две копии нажатого состояния, которые могут создать проблемы. Например, изменение значения переменной state внутри ViewModel вызовет обновление CheckBox , что может закончиться бесконечным циклом. Чтобы избежать этого, нам придется придумывать какой-то костыль.
Использование Compose поможет решить эти проблемы, так как в его основе заложен принцип однонаправленности. Изменение состояния будет обрабатываться внутри фреймворка: мы просто отдаем модель данных внутрь. Кроме того, компонент в Compose теперь не меняет свое состояние самостоятельно. Вместо этого он только вызывает callback, и теперь это задача приложения изменить UI.
5. Улучшение отладки
Так как теперь весь UI написан на Kotlin, теперь можно дебажить UI. Я не попробовал это сам, но в подкасте говорили, что в Compose работают дебаггер и точки остановки.
Хватит слов, покажите код
Я знаю, хочется поскорее увидеть, как выглядит UI в коде (спойлер: очень похоже на Flutter, если вы пробовали писать на нем).
Мы начнем с создания нескольких простых View , затем сравним как они выглядят в существующем UI и в Compose.
1. FrameLayout vs Wrap + Padding + Background
Переиспользуем наш пример выше и попробуем сделать этот TextView с отступами в 30dp и бирюзовым фоном:
Теперь посмотрим на код, который делает то же самое в Compose:
Здесь появляется несколько новых вещей. Так как Text знает только про рендеринг текста, он не заботится об отступах и фоне. Поэтому, чтобы добавить их, нам нужно использовать три отдельные функции:
- DrawRectangle отрисовывает фон
- Padding отрисовывает отступы
- Wrap — функция, которая накладывает параметры друг на друга, как FrameLayout .
Легко. Но немного отличается от существующей UI-системы, к который мы все привыкли.
2. Вертикальный LinearLayout vs Column
Теперь попробуем сделать что-то эквивалентное нашему старому доброму LinearLayout .
Чтобы поместить два элемента один под другим, как на картинке ниже, мы можем использовать Column :
Код будет выглядеть так:
Вложенные в Column элемент будут расположены вертикально друг под другом.
2a. Отступы
Вероятно, вы заметили, что текст и кнопка расположены слишком близко к краю. Поэтому добавим Padding .
2b. Интервалы
Мы можем также добавить немного отступов между Text и Button :
Как выглядит наш экран теперь:
2c. Горизонтальный LinearLayout vs Row
Поместим вторую кнопку рядом с первой:
Внутри Row две кнопки будут расположены горизонтально. WidthSpacer добавляет расстояние между ними.
2d. Gravity vs Alignment
Выровняем наши элементы по центру, как это делает gravity в текущем UI. Чтобы показать diff, я закомментирую старые строки и заменю их новыми:
У нас получится:
С crossAxisAlignment = CrossAxisAlignment.Center вложенные элементы будут выравнены по горизонтали по центру. Мы должны также выставить Row параметр mainAxisSize = FlexSize.Min , похожий по поведению на layout_width = wrap_content , чтобы он не растягивался по всему экрану из-за дефолтного mainAxisSize = FlexSize.Max , который ведет себя как layout_width = match_parent .
2d. Замечание
Из того, что мы видели в примерах выше, можно заметить, что все элементы строятся композитно из отдельных функций: padding — отдельная функция, spacer — отдельная функция, вместо того, чтобы быть свойствами внутри Text , Button или Column .
Более сложные элементы, такие как RecyclerView или ConstraintLayout находятся в разработке: поэтому я не смог найти пример с ними в демонстрационных исходниках.
3.Стили и темы
Вы, вероятно, заметили, что кнопки выше по умолчанию фиолетовые. Это происходит потому, что они используют стили по умолчанию. Рассмотрим, как работают стили в Compose.
В примерах выше FormDemo помечена аннотацией @Composable . Теперь я покажу, как этот элемент используется в Activity :
Вместо функции setContentView() мы используем setContent() — функция-расширение из библиотеки Compose.kt .
CraneWrapper содержит дерево Compose и предоставляет доступ к Context , Density , FocusManager и TextInputService .
MaterialTheme позволяет кастомизировать тему для элементов.
Например, я могу изменить основной цвет темы (primary color) на каштановый следующим образом:
Теперь наш экран будет выглядеть так:
Другие цвета и шрифты, которы можно поменять: MaterialTheme.kt#57
Rally Activity содержит хороший пример, как можно кастомизировать тему: source code to RallyTheme.kt
Что посмотреть/почитать
Если вы хотите большего, вы можете собрать проект-образец по инструкции тут.
Как пишут пользователи Windows, сейчас не существует официального способа запустить Compose, но есть неофициальный гайд из kotlinlang Slack.
Вопросы про Compose можно задать разработчикам в канале #compose kotlinlang Slack.
Оставляйте другие ссылки в комментариях — самые полезные добавлю сюда.
Выводы
Разработка этой библиотеки идет полным ходом, поэтому любые интерфейсы, показанные здесь могут быть изменены. Остается еще множество вещей, про которые можно узнать в исходном коде, как например @Model и Unidirectional data flow (однонаправленный поток данных). Возможно, это тема для будущих статей.
Источник
Погружение в Jetpack Compose
Всем привет. Перед уходом на выходные спешим поделиться с вами еще одним переводом, подготовленным специально для студентов курса «Android-разработчик. Продвинутый курс».
Пробуем новый UI-фреймворк для Android-приложений
В течение последних нескольких лет, участвуя во многих мобильных проектах, мне приходилось использовать различные технологии, например, такие как Android, ReactNative и Flutter. Переключение с ReactNative обратно на классический Android вызвало у меня смешанные чувства. Возвращение к Kotlin прошло хорошо, но я очень скучал по UI-фреймворку React. Небольшие повторно используемые компоненты, с помощью которых создается пользовательский интерфейс, великолепны и обеспечивают большую гибкость и скорость разработки.
Вернувшись в классический Android, мне нужно было беспокоится о том, чтобы сохранить иерархию View как можно более однообразной. Из-за этого трудно по-настоящему посвятить себя компонентному подходу. Это делает копипаст более заманчивым, что приводит к более сложному и менее поддерживаемому коду. В конечном итоге мы удерживаем себя от экспериментов с пользовательским интерфейсом, которые могли бы улучшить UX.
Android раскрывает Jetpack Compose. Иллюстрация: Эмануэль Багилла (Emanuel Bagilla)
Jetpack Compose спешит на помощь
Поэтому после просмотра What’s new in Android с конференции Google I/O 2019 я сразу же начал разбираться с Compose и постарался больше узнать о нем. Compose — это инструментарий реактивного пользовательского интерфейса, полностью разработанный на Kotlin. Compose выглядит очень похоже на существующие фреймворки пользовательских интерфейсов, такие как React, Litho или Flutter.
Нынешняя структура UI-фреймворка Android существует с 2008 года, и со временем стала более сложной, ее довольно тяжело поддерживать. Jetpack Compose стремится начать все с начала с учетом философии современных компонентов. Фреймворк написан с учетом следующих основных целей:
- Несвязанность с релизами платформы: Это позволяет быстро исправлять ошибки, поскольку Compose не зависит от новых релизов Android.
- Меньший стек технологий: Фреймворк не заставляет вас использовать View или Fragment при создании пользовательского интерфейса. Все элементы являются компонентами и свободно могут быть составлены вместе.
- Прозрачные управление состояниями и обработка событий: Одна из самых важных и сложных вещей, которую необходимо решать в больших приложениях, — это обработка потока данных и состояния в вашем пользовательском интерфейсе. Compose проясняет кто отвечает за состояние и как должны обрабатываться события, подобно тому, как это обрабатывает React.
- Написание меньшего количества кода: Написание пользовательского интерфейса в Android обычно требует большого количества кода, особенно при создании более сложных layout’ов, например, с помощью RecyclerView. Compose призван значительно упростить способ создания пользовательского интерфейса.
Это облегчает создание изолированных и повторно используемых компонентов, что упрощает создание нового экрана с существующими элементами. Помогая вам, как разработчику, сосредоточиться на создании удобного пользовательского интерфейса, вместо того чтобы пытаться контролировать View-иерархию и приручать View и Fragment.
Простое приложение с Compose: Hello World
Давайте посмотрим на код простого приложения «Hello World» с Jetpack Compose.
В методе onCreate мы задаем содержимое нашего приложения, вызывая setContent . Это метод, который инициализирует составное дерево виджетов и оборачивает его в FrameLayout .
Чтобы все заработало, нам нужно обернуть наше приложение в CraneWrapper и MaterialTheme . CraneWrapper отвечает за настройку поставщиков для Context , FocusManager и TextInputService . MaterialTheme необходим для предоставления цветов, стилей и шрифтов ваших виджетов. Имея это в виду, мы можем добавить компонент Text , который будет отображать наш текст на экране в определенном стиле.
Введение состояния
Управление потоком данных и состояниями может быть сложной задачей. Чтобы проиллюстрировать, насколько это легко с Compose, давайте создадим простое приложение-счетчик.
Для работы с состояниями Jetpack Compose использует идеи других современных UI-фреймворков, таких как Flutter и React. Существует однонаправленный и реактивный поток данных, который заставляет ваш виджет обновляться или «перекомпоновываться».
В примере выше мы добавляем кнопки «Add» и «Subtract» вместе с лейблом, отображающим текущее количество нажатий. Как вы можете видеть в примере ниже, обновляя состояние «amount», виджеты разумно перекомпоновываются при изменении состояния.
Запуск демо-приложения
Состояние amount инициализируется с помощью +state < 0 >. Пытаясь выяснить, что это за колдовство, я залез в исходный код. Это мое мнение, хотя я все еще не уверен, что до конца все понимаю.
state <. >создает Effect State T code>> . Класс Effect является нечетким классом, который содержит блок исполняемого кода, который выполняется позиционно в контексте композиции. Класс State содержит одно значение с типом Model , по сути делая это значение наблюдаемым (observable). Оператор + является временным оператором, который разрешает State из Effect .
Пользовательские модели состояний
Вместо использования +state <> для создания модели отдельного значения мы также можем создать пользовательскую модель с помощью аннотации @Model. Мы можем улучшить наше приложение-счетчик, разделив его на более мелкие виджеты и передав модель другим виджетам, которые обновляются и отображают состояние этой модели.
Используя аннотацию @Model , плагин Compose Compiler делает все переменные в вашей модели наблюдаемыми, чтобы их можно было использовать для перекомпоновки виджетов. Давайте обновим наш виджет, чтобы использовать CounterModel :
Единственный виджет, из которого состоит приложение-счетчик, теперь разделен на несколько меньших компонуемых виджетов. CounterModel передается различным виджетам, либо для отображения состояния модели, либо для изменения состояния модели с помощью функций add() или subtract() .
Больше никаких view
Важно понимать, что виджеты Jetpack Compose не используют под капотом view или fragment, это всего лишь функции, которые рисуют на холсте. Плагин Compose Compiler обрабатывает все функции с аннотацией @Composable и автоматически обновляет UI-иерархию.
Например, виджет Divider состоит из виджета Padding , который содержит виджет DrawFillRect . Глядя на исходный код DrawFillRect , становится ясно, что он рисует линии прямо на холсте. Все остальные виджеты реализованы таким же образом.
Исходный код DrawFillRect, который используется внутри виджета Divider
Если мы посмотрим на Layout Inspector, запустив один из примеров приложений от Google, ясно увидим, что при запуске приложения Android с Compose нет никаких View или ViewGroups . Мы видим FrameLayout , содержащий CraneWrapper , который мы создали в коде, оттуда на экране отображается иерархия Compose UI.
Layout Inspector инспектирует приложение Jetpack Compose.
Отсутствие views также означает, что Jetpack Compose не может использовать доступные в настоящее время view, такие как android.widget.Button , и должен создавать все виджеты с нуля. Если взглянуть, например, на Flutter, в котором используется тот же подход, то можно увидеть, что это тяжелая работа. Это одна из причин почему Jetpack Compose понадобится время, прежде чем он будет готов к использованию в продакшене.
Все элементы являются виджетами
Совсем как у Flutter, в Compose все элементы — это виджеты. Более сложные виджеты были разбиты на элементарные виджеты с четкими обязанностями. Поэтому даже padding, spacers и так далее являются виджетами. Например, если вы хотите добавить отступ вокруг кнопки, просто оберните ее в padding виджет:
Соединение кода с пользовательским интерфейсом
Соединять Kotlin-код с UI-виджетами очень легко. Например, если вы хотите показать пользовательский интерфейс, которые повторяется или зависит от каких-то условий. Так, вы можете легко отобразить список имен, как показано ниже.
Это действительно мощная фича, но вы должны быть осторожны, чтобы не запрограммировать слишком много логики на уровне пользовательского интерфейса.
Совместимость с вашими Android-приложениями
Compose разработан таким образом, что вы можете добавить его в уже существующее приложение и постепенно перенести некоторые части вашего UI в новый фреймворк. Приведенные выше примеры добавляют Jetpack Compose UI к одному activity. Также вы можете встроить Compose-виджеты в существующий XML layout с помощью аннотации GenerateView :
Заключение
Я в восторге от Compose, потому что он уменьшает растущие страдания, которую я испытываю при разработке под Android. Он помогает быть более гибким, фокусироваться на создании удобного пользовательского интерфейса, а четкая ответственность также позволяет избежать ошибок.
У Compose впереди долгий путь, на мой взгляд, его можно будет использовать в продакшене не раньше чем через год или два. Тем не менее, я думаю, что сейчас подходящий момент, чтобы взглянуть на Jetpack Compose. Создатели активно ищут фидбек, на этом этапе все еще можно вносить изменения. Все отзывы помогут улучшить этот новый фреймворк.
Прочитайте мою статью «Try Jetpack Compose today», чтобы узнать, как подключить пре-альфа Compose. Также, я думаю, вам очень интересно будет посмотреть видео по шаблонам декларативного интерфейса с Google I/O.
Я с нетерпением жду, когда смогу использовать Compose в реальных Android-приложениях!
Вот и все. Ждем ваши комментарии и отличных всем выходных!
Источник