eFusion 30 декабря 2020

📱 Jetpack Compose – до и после

В этой статье мы разберемся, как на примере Tivi изменится скорость сборки, размер APK и объем кода после миграции приложения на Jetpack Compose.

Перевод публикуется с сокращениями, автор оригинальной статьи Chris Banes.

Приложение

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

Tivi сильно модулированный софт. Каждый «экран» UI завернут в собственный модуль Gradle (ui – $NAME). Каждый из этих экранов реализован в виде фрагмента, а затем собран вместе с помощью AndroidX Navigation. Чтобы дать вам представление о его структуре, рассмотрим граф:

Большинство фрагментов ничего не знали друг о друге, поскольку навигационный граф был реализован с использованием deep link URIs. Помимо удобного построения ссылок, эта штука реализует независимую компиляцию модулей, которая помогает строить параллелизм.

Примечание
Модульная структура Tivi совсем неидеальна и приложение не метит на звание лучшего. Присутствует слишком много зависимостей модулей UI (вверху) от базовых модулей (внизу). В идеале каждый слой должен быть отделен.

Прежде чем была начата миграция на Compose, в Tivi использовались все классные UI-штуки, доступные разработчикам Android: Data Binding, Epoxy, Material Design Components, Insetter DBX, MotionLayout и многие другие.

Первый этап

Модульная природа всего приложения означала, что сама миграция может быть выполнена только по частям – по одному фрагменту за раз, что и было сделано в течение 11 месяцев и 46 pull-реквестов.

Приложение по-прежнему использует фрагменты и навигацию, но следующим логическим шагом является отказ от фрагментов и прямое использование нового компонента Navigation Compose.

А теперь давайте рассмотрим некоторые показатели.

Метрики

Для каждой из приведенных ниже метрик мы сравним три различные версии приложения:

  • Pre-Compose. Это коммит, выполненный до первого PR. В нем добавлена поддержка Compose.
  • Mid-transition. В этом коммите, все UI-экраны реализованы в Compose, но AppCompat и MDC все еще местами показываются.
  • Entirely Compose. Данный PR знаменует полное удаление всех следов AppCompat, MDC и т. д.

Размер APK

Показатель, больше всего интересующий пользователей – размер APK.

Результаты приведены для уменьшенного релиза APK (с использованием R8), с применением resource shrinking и измерением с помощью APK Analyzer.

Диаграмма, показывающая размер APK Tivi
Диаграмма, показывающая размер APK Tivi
Диаграмма, показывающая метод подсчета Tivi
Диаграмма, показывающая метод подсчета Tivi

Немного о цифрах

  • На графике изображен размер APK-файла из APK Analyzer, а не размер после загрузки.
  • Как для Mid-transition, так и Entirely Compose (отмечены *) общий размер APK равен 560 КБ из-за дополнительных файлов TTF, которых не было в Pre-Compose APK. Это связано с тем, что Compose не поддерживает загружаемые шрифты (проблема отслеживания), поэтому необходимо включить их в пакет. Столбец «adjusted» показывает более правильное сравнение, исключая файлы шрифтов.
  • Mid-transition имеет увеличенный размер, потому что он включает в себя как Jetpack Compose, так и AppCompat, MDC и т. д.
  • В течение всего процесса миграции было много обновлений зависимостей, в основном библиотеки рантайма – скорее всего это повлияло на метрики размера APK.
  • Также был обновлен Gradle (с 6.0.1 до 6.7.0), плагин Android Gradle (с 3.6.0 до 4.2.0) и Kotlin (с 1.3.61 до 1.4.20) – они могут оказать влияние на скорость билда.

При сравнении «adjusted» значений с «Pre-Compose» мы наблюдаем уменьшение размера APK на 41% и сокращение размера методов на 17% при использовании Compose.

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

Количество кода

Да, подсчет исходных строк кода не является особенно полезной статистикой при сравнении программных проектов, но он дает представление о том, как все меняется.

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

        cloc . --exclude-dir=build,.idea,schemas
    

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

Интересно также, что общее количество кода в Kotlin тоже снизилось. Теперь в проекте меньше шаблонного кода, и автор смог удалить много кода view helper & utility.

Скорость сборки

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

Тестовая установка

Измерения, приведенные ниже, были произведены на разных процессорах.

Тестовая машина – это Lenovo P920 с 192GB ОЗУ и производительным процессором Xeon Gold 6154. Ясное дело, что такая конфигурация не является типичной для разработчика, поэтому чтобы сделать тест более реалистичным, производительность процессора была урезана до минимальной тактовой частоты:

        # Use performance governor to allow tweaking of max freq
sudo cpupower frequency-set -g performance
# Set max frequency to CPU minimum: 1.2GHz
sudo cpupower frequency-set -u 1.2GHz
    

Для подготовки удаленного кеша использовали команду:

        ./gradlew assembleDebug
    

Чтобы запустить тесты, следующая команда была выполнена в цикле 5 раз:

        ./gradlew --profile \
           --offline \
           --rerun-tasks \
           --max-workers=4 \
           assembleDebug
    

Параметр --max-workers не является строго необходимым, но Gradle будет использовать все 64 ядра, доступные на этом процессоре по умолчанию. Ограничение до 4 более сопоставимо с типичными процессорами ноутбуков.

Результаты

Вы можете увидеть результаты тестирования ниже, используя значение «Total Build Time» из каждого отчета.

Результат показал удивительные значения, потому как цифры очень близки. Ожидалось, что «Entirely Compose» будет быстрее, из-за удаления процессоров аннотаций.

Детализация результатов показывает, что время выполнения kapt остается одинаковым во всех прогонах, вероятно, потому что в проекте все еще используется Dagger/Hilt и Room.

Заключение

Можно сделать следующий вывод: Compose оказывает положительное (или нейтральное) влияние на большинство метрик программиста. Имея это в виду, наряду со значительно возросшей производительностью труда использующих Compose разработчиков – это будущее создания пользовательского интерфейса на Android.

Дополнительные материалы:

Источники

МЕРОПРИЯТИЯ

Комментарии 0

ВАКАНСИИ

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ

BUG