В июле этого года вместе с 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:

ext {
   compose_version = '1.0.1'
}
В build.gradle модуля укажем следующие строки:
android {
   ...
   buildFeatures {
      compose true
   }
   composeOptions {
      kotlinCompilerExtensionVersion compose_version
      kotlinCompilerVersion '1.5.21'
   }
   ...
}
dependencies {
   implementation "androidx.compose.ui:ui:$compose_version"
   implementation "androidx.compose.material:material:$compose_version"
   implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
   implementation 'androidx.activity:activity-compose:1.3.1'
}

Здесь мы указываем, что в проекте будем использовать Jetpack Compose и объявляем необходимые зависимости (подробнее про зависимости можно почитать в официальном гайде).

Дальше всё просто. В активити (activity) объявлем Composable-функцию, строим иерархию вьюх с указанием необходимых атрибутов и смотрим результат. 

Пройдемся по коду. Я написал две реализации вёрсток различной сложности:

1. Простая реализация

@Composable
fun Greeting(name: String) {
   Text(text = "Hello $name!")
}

Добавляет TextView в вёрстку с текстом с конкатенацией Hello и аргумента, переданного в Greeting.

Важно отметить, что имена Composable-функций начинаются с заглавной буквы. Это соглашение по наименованию функций, поэтому если писать со строчной, то студия будет подсвечивать неверный нейминг.

2. Более сложная реализация

@Composable
fun ComplexComposeContent() {
   val scrollState = rememberScrollState()
   Column(
      modifier = Modifier.verticalScroll(scrollState)
         .padding(16.dp)
         .fillMaxSize()
   ) {
      Text(text = stringResource(id = R.string.article_title))
      Spacer(modifier = Modifier.height(16.dp))
      Image(painterResource(id = R.drawable.ic_atom), "atom", modifier = Modifier.wrapContentHeight())
      Spacer(modifier = Modifier.height(16.dp))
      Text(text = stringResource(id = R.string.text))
      Spacer(modifier = Modifier.height(16.dp))
      Button(onClick = {}, modifier = Modifier.fillMaxWidth()) {
         Text(text = stringResource(id = R.string.close_caption))
      }
   }
}

Этот вариант представляет собой скролящийся экран, который содержит изображение, текст и кнопку. Рассмотрим некоторые особенности:

  • Необходимо объявить Scroll State. Только не обычный, а тот, который позволяет сохранять состояние скролла сквозь рекомпозицию — rememberScrollState().

  • Column представляет собой ViewGroup с вертикальным расположением элементов. 

  • Modifier позволяет управлять атрибутами, добавлять декорации и поведение к вьюхам.

Остальное интуитивно понятно. И это как раз одна из ключевых особенностей Jetpack Compose — даже если вы не использовали библиотеку ранее, то всё равно с ней разберётесь.

Добавить вьюхи в активити можно через extension setContent {}, например:

override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContent {
   		Greeting("Android")
	}
}

В общем-то, создание UI выглядит действительно просто. Теперь определим, насколько сильно оптимизируется приложение и как быстро пользователь увидит окончательный экран. 

Для тестирования воспользуемся библиотекой Jetpack Benchmark, о которой, кстати, тоже рассказывали в отдельной статье. Код теста выглядит так:

@RunWith(AndroidJUnit4::class)
class LayoutBenchmark {
   
   @get:Rule val activityRule = createAndroidComposeRule(MainActivity::class.java)
   
   @get:Rule val benchmarkRule = BenchmarkRule()
   
   @Test
   @UiThreadTest
   fun testSimpleResourceLayout() {
      activityRule.activity.let {
         benchmarkRule.measureRepeated {
            it.setSimpleResourceContent()
         }
      }
   }
   
   @Test
   @UiThreadTest
   fun testSimpleViewLayout() {
      activityRule.activity.let {
         benchmarkRule.measureRepeated {
            it.setSimpleViewContent()
         }
      }
   }
   
   @Test
   @UiThreadTest
   fun testSimpleComposableLayout() {
      activityRule.activity.let {
         benchmarkRule.measureRepeated {
            it.setSimpleComposableContent()
         }
      }
   }
…
}

Протестируем три версии установки вьюхи в активити:

  1. При передаче ресурса в setContentView.

  2. При передаче вьюхи в setContentView.

  3. С Composable-функцией.

Итоги тестирования можно посмотреть в таблице: левый столбец — название теста, правый — время на выполнение:

Тест

Время теста

LayoutBenchmark.simpleResourceLayout

84 291 ns 

LayoutBenchmark.complexResourceLayout

964 792 ns

LayoutBenchmark.simpleViewLayout

2 481 ns 

LayoutBenchmark.complexViewLayout

126 024 ns 

LayoutBenchmark.simpleComposableLayout

94 ns

LayoutBenchmark.complexComposableLayout

88 ns

Вывод простой — Composable-функция работает быстрее каждого из предыдущих вариантов в несколько раз. Так что в копилку преимуществ добавляется и быстрый показ UI пользователю.

Вместо заключения

Недостаток библиотеки есть, но очень субъективный — если неверно декомпозировать и экран имеют большую вложенность, то функция разрастётся в непрезентабильный вид. А такой код уже сложнее поддерживать. Пожалуй, на этом минусы заканчиваются.

Jetpack Compose новый и амбициозный инструмент, позволяющий декларативно и в понятном формате описывать пользовательский интерфейс. Его определённо стоит попробовать.

Комментарии (15)


  1. AlexeyGorovoy
    26.09.2021 22:30
    +5

    2. Интуитивно понятный.


    ИМХО ну ооочень сильно притянуто за уши. Ровно теми же словами можно и про XML сказать - разработчику нужно лишь сказать какие view он хочет видеть на экране, остальное ляжет на плечи стандартного фреймворка.

    Интуитивным компоуз станет только когда разработчик окончательно перестроится на новый вид мышления. Наверное. Я сам пока ещё не там, старые привычки слишком сильны.

    А ещё мне кажется вы упускаете самый главный недостаток компоуза - он тупо ещё слишком новый.

    Слишком новый чтобы легко нагуглить нужное решение (в том числе и для простых вещей);
    слишком новый чтобы всегда стабильно и правильно работать;
    слишком новый чтобы быть достаточно распространенным;
    слишком новый чтобы за хайпом видеть реальную ценность... список можно продолжать.

    Я к чему это - учить его уже надо и у меня нет сомнений что в будущем он станет стандартом, но пока что к нему больше вопросов чем реальной осязаемой для бизнеса пользы.

    В конце концов попробуй объясни менеджменту зачем всей команде сейчас учиться писать на компоузе если все текущие задачи мы можем сделать "старым" способом :)

    Поэтому лично мне не нравится все эти излишне позитивные и поверхностные статейки про компоуз, добавляйте хоть долю реалистичной критики. Давайте все дружно чаще забрало протирать чтобы от хайпа не запотевало.


    1. AWE64
      27.09.2021 14:33
      +1

      Полноте, о какой объективности речь, это же стандартный стиль восторженного повествования о новой вундервафле: котлин - "интуитивно понятный", корутины - "интуитивно понятные", теперь вот это.


    1. i15in Автор
      27.09.2021 18:51
      +2

      По большей части я согласен. Любая новинка должна тщательно тестироваться и критиковаться, но тот факт, что инструмент ещё новый, не говорит о том, что его не стоит пробовать. С наличием решений проблем пока не возникало, помимо того на официальном сайте Android разработки есть хорошая документация (хотя возможно у меня не было достаточно сложных экранов). Главное понять принцип, а дальше всё идет по накатанной. И да, к нему нужно привыкать и в большинстве случаев это дело вкуса.


  1. Mox
    27.09.2021 00:40
    +3

    Я немного офигел когда узнал что Compose использует тот же skia что и flutter. И подход к построению очень похожий. Почему JetBrains просто не прикрутят kotlin k flutter - я не знаю (


    1. shok96
      27.09.2021 04:03

      потому что flutter это гугл
      а котлин это jetbrains)

      А вообще флуттер это дарт фреймворк и он не совместим с котлин
      он только компилируется в джава

      Видимо нужно полностью переписывать flutter под котлин


      1. bean
        27.09.2021 05:46
        +3

        Flutter (а точнее dart) компилируется в натив на андроиде, в apk попадает *so под разные архитектуры, на стороне джавы написана обертка, которая эти сошки загружает, создает view и на ней уже флаттер рисует через skia.

        Compose же на андроиде использует стандартные механизмы отрисовки, а skia используется только для desktop'a, через обертку которую делает JetBrains, но это пока альфа версия.


  1. bean
    27.09.2021 05:48
    +2

    Очень странный бечмарк, compose наверное быстр, но больше похоже на что Jetpack Benchmark не умеет работать с Compose и там код не запускался вообще, слишком большая разница.


    1. i15in Автор
      27.09.2021 18:51
      +2

      Я использовал правило, которое создаётся при помощи createAndroidComposeRule. Оно как раз нужно для установки compose-контента в активити. Плюс на тестах видно, что экран прогружается.


  1. deinlandel
    27.09.2021 09:11
    +2

    Именно из-за «интуитивности» Compose есть целые циклы статей о том, что такое «remember», как избежать рекомпозиции, как, черт возьми, делать альтернативные лэйауты для разных видов экранов устройств и landscape/portrait, как по человечески работать с темами и делать анимации/drag'n'drop/bottomsheet и прочие вещи, которые в обычных вьюхах давно тривиальны и т.д.


    1. AlexeyGorovoy
      27.09.2021 18:19
      +2

      А то классное чувство когда сидел изучал несколько дней и думаешь что вот уже получается, и стейты наконец осознал и понял... И тут случайно попадаешь например р на страничку про сайд-эффекты в компоузе и понимаешь как же много тебе ещё вникать :)


    1. i15in Автор
      27.09.2021 18:52
      +2

      Считаю Compose амбициозным проектом, который должен охватить довольно широкий функционал. Поэтому да, прочитать достаточное количество документации и статей, чтобы его хорошо освоить, придётся. Субъективно по базовым механизмам интуитивно понятно. Его как минимум стоит попробовать, а использовать ли на проде — другой вопрос.


  1. Amareis
    27.09.2021 13:20
    +1

    Хе-хе, реакт с хуками наконец-то и до мобилок добрался. Разве что реализация хуков здесь гораздо более правильная, из-за того что используется плагин для компилятора.


  1. somarov
    29.09.2021 19:43

    minSdkVersion 21

    не самый лучший стимул для перехода на Jetpack Compose, далеко не все могут проигнорировать пользователей старых версий android учитывая, что статистика по приложению подсказывает несколько менее оптимистичный расклад по версиям чем подсказка Android Studio при создании проекта.


  1. superkeka
    29.09.2021 19:43
    +1

    бещает быть революцией в построении UI

    Расскажите это QML, которому 12 лет


    1. Calc
      22.10.2021 15:15

      Современные мобильные разработчики тогда только школу заканчивали :)