Основы работы с приложениями

Переход приложения Google Play на Jetpack Compose после 20 лет работы

Колонки

  • Кирилл Гручников (Kirill Grouchnikov)

    Разработчик ПО

  • Джон Букеноген (Jon Boekenoogen)

    Разработчик ПО

О приложении

О выступлении

В этом году Compose официально стал основным инструментом для создания пользовательских интерфейсов в Android, а устаревшие представления были переведены в режим обслуживания. Для Google Play этот путь начался в 2020 году. Переход на Jetpack Compose, который затронул миллиарды пользователей и потребовал почти два десятилетия работы инженеров, был осуществлен благодаря проверенным рекомендациям, тесному сотрудничеству с основной командой Compose и непрерывному развитию инструментов.

Узнайте, как модернизация Google Play с помощью Compose позволила заметно повысить скорость работы и долгосрочную стабильность. На этом занятии мы расскажем, как связать рабочие процессы проектирования Figma с реализацией Compose, автоматизировать контроль качества, чтобы предотвратить ненужные рекомпозиции, и создать выразительные интерфейсы с динамическими цветами, разнообразной типографикой и многослойными фигурами. Вы узнаете о проверенных стратегиях, которые помогут быстрее сортировать ошибки и уверенно масштабировать переход на Compose.

Сводка

  • За шесть лет Google Play перевел 97 % показов пользователям на экраны, созданные только с помощью Compose. За последние 14 месяцев на основных страницах на 30 % снизилась частота задержек.
  • Постепенное внедрение снижает бизнес-риски в больших базах кода. Команды могут сначала ознакомиться с экранами с низким трафиком, а затем перейти к размещению ComposeView непосредственно в корне Activity.
  • Динамические темы полностью работают в коде с использованием оверлеев MaterialTheme и библиотеки Material Color Utilities. Это позволяет избежать разбора Activity, хотя создание цветовых схем во время сборки помогает ограничить задержку во время выполнения.
  • Однонаправленный поток данных и декларативный пользовательский интерфейс упрощают архитектуру и устраняют несколько типов состояний гонки. Параллельная обработка источников данных и преобразований интерфейса позволила сократить задержку загрузки Google Play на десятки миллисекунд.
  • Автоматизированные проверки Lint обеспечивают качество кода и соблюдение правил системы проектирования. Google Play использует их, чтобы блокировать цвета, заданные в коде, и помечать потенциальные проблемы с производительностью, например BoxWithConstraints.

Gemini Notebook

Темы

  • jetpack-compose
  • перенос
  • производительность
  • тематическая привязка
  • unidirectional-data-flow
  • lint-rules
  • developer-velocity

Расшифровка

Введение и внедрение Google Play

  • Всем привет!

  • Меня зовут Александр.

  • Я представляю команду Google Play.

  • Это мой коллега Кирилл.

  • Сегодня мы расскажем, как перенесли большую часть кода из системы View и Fragment в Compose.

  • Давайте начнем.

  • Как проходило внедрение и насколько масштабным оно было?

  • База кода нашего приложения росла органически с 2007 года.

  • У нас несколько миллионов строк кода, 200 экранов и 500 уникальных компонентов интерфейса, которые используются на многих из этих экранов.

  • В 2020 году мы поняли, что скорость разработки, надежность и производительность не соответствуют нашим целям.

  • Поэтому мы решили перейти на современный набор технологий для пользовательского интерфейса.

  • Мы оценили множество разных библиотек.

  • В то время мы также общались с коллегами из AndroidX, которые рассказали нам о Compose. Мы решили внедрить этот инструмент и стали его первым крупным партнером.

  • Как прошло?

  • Шесть лет спустя 97 % показов в приложении Google Play приходится на экраны, созданные только с помощью Compose.

  • С 2020 года вся разработка для телефонов и больших экранов перешла на Compose.

  • И даже наши расширенные форм-факторы, XR, TV, Auto, Wear, перешли на Compose с 2025 года.

  • И Compose сыграл в этом успехе очень важную роль, поэтому мы продолжаем внедрять его все больше и больше.

  • У них был очень мощный и комплексный набор тестов, который помог нам внедрять новые версии Compose дважды в неделю.

  • Мы используем альфа-сборки и новые API, чтобы исправлять ошибки, повышать производительность и предлагать пользователям новые возможности.

  • Если говорить о производительности, Compose действительно обеспечивает стабильную работу нашего приложения на всех основных экранах.

  • Это страница результатов поиска, главная страница, страница сведений.

  • Производительность, задержка загрузки и задержка отрисовки – это очень важные показатели для нашего бизнеса и удобства пользователей.

  • Таким образом, за последние 14 месяцев мы наблюдаем улучшение на 30 %.

План переноса

  • Но как она добилась такой известности?

  • Вот об этом мы и поговорим.

  • Давайте поговорим о плане переноса.

  • Поэтому мы решили действовать поэтапно.

  • Мы не хотели складывать все яйца в одну корзину.

  • Мы предприняли несколько шагов, чтобы понять риски и влияние на наш бизнес, и обрели уверенность, прежде чем полностью перейти на автоматизацию.

  • Я назову их так: ползание, ходьба, бег трусцой и бег.

  • Поэтому на первом этапе мы просто знакомились с Compose.

  • Мы начали со страницы с низким трафиком.

  • Это может быть страница настроек, лицензии третьих сторон и тому подобное.

  • Ваша основная цель — ознакомиться с библиотекой Compose.

  • Это могут быть строки, столбцы, текст, изображения и тому подобное.

  • А затем вам нужно начать переносить всю инфраструктуру вашего приложения и понять, как она работает в Compose.

  • Это могло быть связано с регистрацией показов и кликов, темами, а также с тем, что мы одновременно обновляли загрузку данных.

  • Так что все эти вещи.

  • Чтобы все экраны выглядели единообразно, мы создали модульные и функциональные тесты. Они проверяют, что объекты тем в Compose напрямую сопоставляются со стилями XML, типографикой, цветами и другими элементами.

  • Когда мы привыкли к этому и почувствовали себя уверенно, мы решили перейти к ходьбе.

  • Мы взяли небольшой компонент на экране с очень высоким трафиком и оценили, как будет выглядеть его перенос.

  • Мы рекомендуем взять элемент, который находится в RecyclerView, чтобы вы могли понять любые проблемы совместимости между View и системой Compose, а также увидеть производительность измерений и задержки на этом пути.

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

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

  • У вас есть стек рендеринга, который полностью находится в Compose, и стек, который находится в Views.

  • Поэтому будет происходить некоторая пробуксовка памяти, загрузка дополнительных классов и т. д.

  • Но по мере того, как вы будете все больше и больше внедрять Compose, это исчезнет.

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

  • После ходьбы мы переходим к бегу трусцой.

  • Это когда мы уже очень, очень хорошо освоились.

  • Вместо того чтобы делать один компонент на странице с высоким трафиком, просто сделайте всю страницу с высоким трафиком.

  • Поэтому мы сохранили библиотеку навигации и использовали фрагменты, но для каждого отдельного экрана она была полностью реализована в Compose.

  • Мы просто заставили Fragment вернуть сам ComposeView.

  • Таким образом, вы можете ожидать улучшения задержки и рывков.

  • Вы не будете сталкиваться с проблемами с памятью и загрузкой классов, о которых я говорил.

  • И сам Compose также выполняет некоторые уровни кэширования на уровне ComposeView.

  • Поэтому, если у вас есть RecyclerView с кучей карточек, которые выглядят одинаково и могут иметь одинаковые значки, весь этот синтаксический анализ значков и использование ресурсов распределяются между всеми элементами ComposeView.

  • Поэтому мы перешли к бегу.

  • Вот когда вы действительно идете ва-банк.

  • Когда большая часть трафика вашего приложения будет приходиться на Compose, мы перейдем на следующий уровень.

  • Итак, на приведенных выше экранах у нас есть Activity.

  • Поэтому переместите ComposeView в корень Activity.

  • И большая часть вашего кода будет выглядеть относительно похоже.

  • Вы по-прежнему пытаетесь дать инструкцию по навигации, когда хотите сказать, что нужно перейти с одного экрана на другой.

  • Но вместо транзакций фрагментов вы вызываете composable-функцию.

  • Вы можете сделать это поверх библиотеки Nav2 или Nav3, в зависимости от того, что вы выберете.

  • Нам не удалось перенести все экраны.

  • Я уже говорил, что их много.

  • Поэтому мы создали совместимость с фрагментами, где у вас может быть экран на основе фрагментов, и использовали для этого оболочки AndroidFragment в Compose.

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

  • но и новые возможности.

  • Справа вы видите пример GIF-изображения, в котором можно использовать переходы между экранами с общими элементами.

  • У нас есть изображение, которое увеличивается по мере перехода от одного экрана к другому, и это обеспечивает непрерывность.

  • Вы также можете использовать все возможности анимации Compose во время всего перехода.

  • А теперь я передаю слово Кириллу, который расскажет о других возможностях.

Темы и производительность

  • Спасибо, Александр.

  • Я хочу немного поговорить о теме, которая мне близка и дорога, а именно о темах и стилях для приложений Android, чем я занимаюсь уже некоторое время.

  • В мире View был код Java, а чуть позже код Kotlin, а затем были ресурсы X-- XML, такие как цвета, строки, размеры, макеты, темы и стили.

  • Все эти XML-ресурсы компилировались в таблицу ресурсов, которая включалась в APK-файл и была практически статической.

  • Существует API Resources.Theme.applyStyle, который можно использовать динамически во время выполнения, чтобы применять собственный стиль поверх иерархии пользовательского интерфейса.

  • Основное ограничение заключалось в том, что это нужно было делать до использования метода inflate контента. То есть, если вы хотели динамически применить стиль к существующему элементу пользовательского интерфейса, вам приходилось удалять и заново создавать все Activity, что было не очень удобно для пользователя.

  • Кроме того, поскольку применялись предварительно скомпилированные блоки XML, было сложно комбинировать несколько условных динамических оверлеев друг с другом на основе флагов эксперимента или других бизнес-требований.

  • Было довольно сложно построить правильную ментальную модель иерархии стилей в этом мире XML.

  • И наконец, в Android Studio или любом другом инструменте разработки не было единого унифицированного представления, которое позволяло бы преодолеть разрыв между миром Java, миром кода и миром XML.

  • И было довольно сложно жонглировать и строить правильную ментальную модель и отлаживать, почему мой стиль не применяется, почему я получаю неправильный цвет и так далее.

  • В новом мире, в мире Compose, в частности для системы Material Design и библиотеки Compose Material, а также для других систем проектирования, у нас есть MaterialTheme Composable, который вы применяете к самому верху иерархии пользовательского интерфейса на экране, и вы также можете применить эту MaterialTheme в качестве наложения на любую меньшую часть вашего пользовательского интерфейса.

  • Если вы посмотрите на экран справа, то увидите вверху карточку Play Points Gold с индикатором прогресса и текстом.

  • Мы применяем этот оверлей тематического оформления Material Design с пользовательской цветовой схемой, созданной библиотекой Material Color Utilities, которая доступна на GitHub.

  • Мы передаем этот коричневато-желтый, золотой цвет в качестве начального значения, и он генерирует полный спектр токенов цвета материала, первичный на первичном, вторичный на вторичном, которые мы затем используем внутри реализации этой карты.

  • Это дает разработчикам Android полный доступ к возможностям динамических тем.

  • Все делается в коде, все делается в Kotlin, а это значит, что гораздо проще построить правильную ментальную модель того, как все это работает, и гораздо проще отлаживать.

  • А внутри эти наложения прикрепляются как локальные композиции к конкретным узлам пользовательского интерфейса в вашей иерархии, где вы решите их применить.

  • Рекомендации по производительности: создание полной цветовой схемы с помощью библиотеки Material Color Utilities не является бесплатным.

  • Это связано с определенными накладными расходами.

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

  • Итак, во-первых, вы хотите начать измерять, как это влияет на вашу производительность, и, во-вторых, вы можете перенести часть этих накладных расходов со времени выполнения на время сборки.

  • Вы можете использовать ту же библиотеку Material Color Utilities во время сборки, чтобы предварительно сгенерировать эти цветовые схемы в соответствии с потребностями вашего бренда или продукта и перенести эти накладные расходы на время сборки.

  • Локальные переменные, которые отслеживают, где именно в дереве иерархии интерфейса находятся оверлеи, гораздо дешевле, но все же не бесплатны.

  • Так что, в зависимости от того, сколько вы используете, десятки, сотни, это начинает складываться.

  • И в какой-то момент вы захотите начать смотреть на стоимость всех этих комбинированных композиционных локалей.

  • Это пример того, о чем я говорил, – настоящие возможности динамического оформления в Compose.

  • Здесь у нас четыре квадранта, одинаковые визуальные эффекты, одинаковые, назовем это карточкой события.

  • У нас есть главное изображение, которое занимает всю карточку, а также ярлык в левом верхнем углу, кнопка в правом нижнем углу и несколько текстов.

  • А справа от каждого из квадрантов вы видите выноску цветовых токенов, которые используются в качестве спецификации дизайна для каждого из элементов.

  • Реализация карточек для всех четырех типов одинакова.

  • Единственное отличие заключается в том, что оверлей тематического оформления Material Design, в который заключена карточка, генерируется или настраивается с помощью динамически создаваемой цветовой схемы на основе доминирующего цвета изображения: синего, фиолетового, желтого и красного.

  • Все остальные условия остаются прежними.

  • Вам не нужно удалять и заново создавать действие.

  • Вы можете применять его условно на основе параметров эксперимента или других бизнес-требований.

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

  • А теперь я передаю слово Джону.

Повышение надежности и скорости

  • Да.

  • Это ещё один пример гибкости, о которой говорил Кирилл.

  • Давайте поговорим о надежности и скорости.

  • Поэтому все разработчики и компании стремятся быстро создавать высококачественный код.

  • Давайте посмотрим, как Compose помог Google Play в этом.

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

  • Не буду вдаваться в подробности, но одна из ментальных моделей, которую пытается внедрить Compose, связана с однонаправленным потоком данных, и это действительно оказало большое влияние на нашу команду.

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

  • Источник данных предоставляет данные.

  • Эти данные могут быть преобразованы в определенный интерфейс, который мы выводим в виде модели интерфейса.

  • И затем Compose может легко наблюдать за этим, просто вызывая свойство value для этого состояния.

  • Это своего рода стрелки вдоль верхней стороны этой диаграммы.

  • а затем события передаются в обратном направлении.

  • Если пользователь нажмет кнопку, это действие будет передано в преобразователь интерфейса, который обновит источник данных, выдаст новое значение и запустит преобразования. Так и работает этот цикл.

  • Так что все проходит через этот относительно простой цикл.

  • Основное преимущество, которое мы заметили, – это сокращение времени на обучение.

  • Больше не нужно думать, где происходят все эти вызовы – в основном потоке или в других.

  • Она следует одному общему циклу.

  • Compose делает наблюдение за данными очень простым, а данные имеют строгие гарантии согласованности между архитектурными уровнями.

  • Ментальная модель сократила количество разговоров об источниках истины в нашей команде и полностью устранила несколько типов состояний гонки.

  • Ещё одно огромное преимущество по сравнению с нашей предыдущей архитектурой "модель-представление-контроллер" заключается в том, что стало очень просто выполнять параллельное выполнение источников данных и преобразований пользовательского интерфейса.

  • Это позволило нам сократить задержку загрузки в магазине на десятки миллисекунд.

  • Это было впечатляюще.

  • В сочетании с однонаправленным потоком данных, другим огромным преимуществом Compose является декларативный пользовательский интерфейс.

  • Кирилл уже немного затронул эту тему.

  • Разработчикам Google Play это тоже очень понравилось.

  • Управление пользовательским интерфейсом теперь осуществляется в одном файле.

  • Справа приведен довольно простой пример.

    @Composable
    fun PurchaseRow(onClick: () -> Unit, modifier: Modifier) {
      Row(modifier) {
        Text("20% off sale")
        if (LocalExpts.current.useButtonV2) {
          ButtonV2("Buy", onClick = onClick)
        } else {
          ButtonV1("Buy", onClick = onClick)
        }
      }
    }
  • Мы меняем две реализации кнопки на основе флага эксперимента.

  • Вместо того, чтобы читать несколько файлов представлений, фрагментов и XML-файлов, вы просто читаете его сверху вниз, и это значительно упрощает задачу.

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

  • Ещё одно преимущество – обратные вызовы жизненного цикла стали намного проще, и их количество сократилось.

  • Поэтому вместо жизненного цикла представления, фрагмента и активности вы получаете одноразовый эффект, побочный эффект, и в зависимости от того, где вы его разместите, он действует очень последовательно.

  • Это очень удобно.

Подготовка к работе с LLM

  • Итак, эти два архитектурных изменения действительно заложили основу для LLM, на мой взгляд, и позволили им генерировать код довольно высокого качества.

  • И я уверен, что многие из вас, вероятно, пробовали это или делали это со своей любимой LLM.

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

  • Однако у него есть свои ограничения.

  • И Google Play не понимает вашу базу кода, верно?

  • Она не знает, какие компоненты вы уже создали и можете использовать повторно, и не знает названий токенов дизайна.

  • Она просто предоставляет вам заданные в коде цвета и строки.

  • Какой контент должен быть с устройства, какой контент должен поступать с сервера или как мне убедиться, что он эффективен при использовании LazyList, а не просто создает огромный столбец?

  • Чтобы решить эту проблему, мы добавили к скриншотам метаданные.

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

  • а также сигнатуру функции высокого уровня, чтобы вы могли указать, какой контент является динамическим, а какой – статическим.

  • В итоге у вас получится что-то вроде того, что у нас было раньше, переходящее в то, что будет после.

  • Я не добавил сюда граничные рамки, потому что они бы загромождали диаграмму.

  • Но вы можете видеть, что эти жестко закодированные цвета и названия типографики заменяются на title large и on surface.

  • Названия компонентов, например заголовок карточки и значок, четко обозначены.

  • Таким образом, их можно найти в вашей базе кода.

  • И для нас, у нас есть, вы знаете, многие из них также поступают из общих библиотек дизайна, о которых Кирилл расскажет через минуту.

  • Поэтому вы не будете постоянно добавлять ко всем этим товарам пользовательские метки.

  • Вы связываете это с сигнатурой метода, как у нас внизу, OfferCard, и тогда он знает, что заголовок, endDate, изображение – все это динамическое.

  • Не следует задавать их в коде.

  • И вместе с этими семантическими именами мы теперь можем переключаться на все эти различные цветовые приложения, о которых говорил Кирилл.

  • И благодаря этому мы генерируем гораздо больше кода.

  • А теперь я передаю слово Кириллу, который расскажет о том, как мы поддерживаем качество.

Автоматизация качества

  • Справа.

  • Спасибо, Александр.

  • Итак, продолжая тему разработки с помощью LLM и Agent Assist, мы сначала начнем со стороны UX-дизайна.

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

  • Может, это Material.

  • Возможно, это ваша собственная система проектирования.

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

  • Чтобы дизайнеры могли быстро переключаться между этими различными комбинациями и видеть, как на это реагируют их спецификации дизайна.

  • Затем, когда он дорабатывается и передаётся на сторону реализации, в этом конвейере экспорта вы хотите иметь какую-то возможность отслеживать, что каждый цвет, каждый элемент типографики, каждая фигура использует соответствующий токен, а не является жёстко закодированным значением RGB, или жёстко закодированным семейством шрифтов, или размером шрифта.

  • И наконец, мы обнаружили, что в Google Play очень полезно использовать не десятки, а сотни компонентов, кластеров, карточек и контейнеров, которые применяются на разных экранах.

  • Мы поняли, что удобно хранить всю эту информацию в одном месте, которое мы называем каталогом компонентов, и обучать на нем специального агента.

  • И это очень полезно, когда вы начинаете работу над новым экраном, новым путем пользователя или новым продуктом. Вы можете загрузить в агент первые наброски дизайна, например слайды или спецификацию Figma, и он быстро определит, какие компоненты уже существуют, чтобы их не нужно было заново проектировать и реализовывать с нуля.

  • И это значительно сокращает затраты на проектирование и затраты на реализацию.

  • Что касается реализации, мы в значительной степени полагаемся на основные и настраиваемые правила Lint.

  • Я хочу выделить два основных правила Lint. Первое – FrequentlyChangingValueDetector. Оно помогает выявлять источники ненужных рекомпозиций, которые могут приводить к задержкам и зависаниям. Второе – ScaffoldPaddingDetector. Оно позволяет отмечать случаи, когда мы используем composable-функцию Scaffold из Material Compose, но игнорируем входящие отступы.

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

  • И, наконец, BoxWithConstraints, он имеет определенные соображения производительности.

  • Для правильного размещения всех элементов может потребоваться два кадра.

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

  • Для автоматизации тем, опять же, токены цвета, токены типографики, токены формы.

  • У нас есть правило Lint, которое блокирует использование жестко закодированных цветов и типографики.

  • У нас есть правило Lint, которое помечает использование компонентов Material 2.

  • Мы хотим использовать только Material 3, самую последнюю и лучшую версию, включая новые выразительные компоненты, которые были представлены в прошлом и этом году.

  • У нас есть специальное правило Lint, которое запрещает считывать цвета, например, из устаревших XML-файлов.

  • Мы хотим использовать Compose в первую очередь и только Compose для новых экранов.

  • А у текстовых composable-функций, особенно в системе проектирования Material Design, есть резервные варианты стиля и цвета.

  • Они считывают его из цвета локального контента и локальной типографики, но мы не хотим на это полагаться.

  • Мы хотим, чтобы каждый текст намеренно использовал определенный стиль, стиль типографики и определенный цвет из спецификации дизайна.

  • Это правило Lint, которое у нас есть.

  • И последнее, по аналогии со ScaffoldPaddingDetector, у нас есть специальное правило Lint, которое гарантирует, что каждая функция Composable, которая у нас есть, использует свой модификатор ввода.

  • Опять же, чтобы предотвратить, например, неправильное размещение новых объектов или несоответствие фону и так далее.

Заключение

  • Это три основных момента, которые мы хотели бы, чтобы вы вынесли из этой презентации.

  • Во-первых, сегодня, в конце 2026 года, Compose – это, по нашему мнению, зрелый набор инструментов для создания пользовательского интерфейса, проверенный в масштабе.

  • Android сам по себе ориентирован на Compose.

  • Ранее в этом году на Google I/O мы объявили, что все библиотеки пользовательского интерфейса и все агентские потоки ориентированы на Compose.

  • И, как Джон упоминал ранее в презентации, ползайте, ходите, бегайте трусцой и бегайте, мы предлагаем вам мигрировать постепенно, особенно большие кодовые базы, чтобы ускорить вашу скорость для потоков разработчиков и для агентских потоков.

  • Спасибо за внимание. Через несколько минут мы с Джоном выйдем к вам и ответим на ваши вопросы.

  • Ещё раз спасибо за ваше время.

Код

Фрагменты кода

Фрагмент кода на Kotlin в видео "Повышение надежности и скорости"
@Composable
fun PurchaseRow(onClick: () -> Unit, modifier: Modifier) {
  Row(modifier) {
    Text("20% off sale")
    if (LocalExpts.current.useButtonV2) {
      ButtonV2("Buy", onClick = onClick)
    } else {
      ButtonV1("Buy", onClick = onClick)
    }
  }
}