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

Kotlin и Android: подведение итогов эксперимента Brass Tacks

Было весело изучать возможности языка Kotlin® для разработки под Android! Если вы попали сюда без этого контекста и хотите изучить эту серию блогов из 7 частей с самого начала, вы можете вернуться к началу, но для понимания этой статьи это не обязательно.

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

На этом этапе у вас может возникнуть следующий вопрос: Стоит ли мне хотя бы попытаться использовать эту технику для создания представлений в моем приложении? До сих пор я говорил только о том, как это может сделать это легко и удобно, но я действительно не сравнивал это ни с чем, кроме той же задачи на языке программирования Java®. В этом отношении я определенно считаю, что использование шаблона построения безопасных типов Kotlin для построения представлений намного удобнее, чем эквивалентная практика в Java. Однако определение представлений в ресурсах XML является стандартом для приложений Android, поэтому давайте разберем несколько категорий для сравнения между классическими макетами XML и подходом конструктора с типобезопасностью Kotlin.

Насколько хорошо этот подход работает с изменениями конфигурации действий?

С Android устройство может изменить конфигурацию в любое время. Наиболее распространенный тип изменения конфигурации - ориентация. Есть много других типов, как описано здесь (см. Android: configChanges внутри). Изменения ориентации особенно важны для представлений Android, поскольку обычная практика - иметь разный макет как для альбомной, так и для портретной ориентации.

Имея дело с макетами XML, легко обрабатывать изменения конфигурации, которые приводят к другому пользовательскому интерфейсу. Вы просто определяете свой макет дважды - один раз для ландшафта в res / layout-land и один раз для портрета в res / layout-port. Когда вы даете файлам XML одно и то же имя в этих разных пространствах, это позволяет Android находить и расширять правильную версию макета для каждого случая. Вообще говоря, вы не пишете никакого дополнительного кода для обработки этого изменения.

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

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

Насколько хорошо этот подход работает для сложных макетов, таких как RelativeLayout?

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

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

При работе с XML-макетами создать новый идентификатор несложно. Вы просто вызываете новое значение там, где оно необходимо, обычно в свойстве android: id представления, например:

<TextView android:id="@+id/tv" ... />

Обозначение + @ id указывает инструментальной цепочке Android определить новый идентификатор с именем tv или повторно использовать существующий идентификатор с тем же именем. Нет ничего проще.

Однако при работе с макетами, созданными из кода, невозможно создать новый идентификатор в середине кода. Чтобы создать новый идентификатор, вы должны определить новый идентификатор как ресурс в XML. Затем вы можете ссылаться на него из скомпилированного класса R, который содержит все идентификаторы, используемые в приложении. Таким образом, программная работа с представлениями предполагает работу с другим файлом, и Android не будет автоматически удалять идентификаторы, если на них больше нет ссылок.

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

Насколько хорошо работает этот подход при выполнении вычислений для присвоения атрибутов представлений?

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

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

Однако при программном построении представления вы можете просто присвоить результат вычисления непосредственно свойству представления. Вы также можете присвоить значения какому-либо другому свойству в представлении. Сколько раз вы присваивали значениям marginLeft и marginBegin одно и то же?

Учитывая, что вы (конечно) обладаете всей гибкостью кода при программном создании представлений, в этом случае определенно удобнее использовать программное создание представлений, особенно с типобезопасными конструкторами Kotlin.

Насколько легко вы можете экспериментировать с настройками макетов?

Если вы действительно не умеете визуализировать макет Android в процессе их написания, вы, вероятно, использовали Android Studio для предварительного просмотра макета XML без необходимости создавать и развертывать на устройстве, чтобы увидеть результат.

Когда вы программируете макеты программно, у вас нет такого метода быстрого предварительного просмотра. Когда Android Studio 2.0 с мгновенным запуском будет полностью выпущен, эта ситуация значительно улучшится. Но на данный момент наиболее удобный способ поэкспериментировать с изменениями макета - это использовать панель предварительного просмотра Android Studio.

Какова эффективность каждого подхода?

Это вопрос сравнения инфляции иерархии представлений с эквивалентным кодом, который напрямую конструирует представления. Когда я впервые начал экспериментировать с этим, я обнаружил, что создание простого макета происходит вдвое быстрее! Но когда я начал добавлять больше функций Kotlin и делать более сложные вещи с представлениями, разница не была такой большой. На своем Nexus 6P я обнаружил, что надувание здания занимает примерно 75% времени. Предположительно, это связано с тем, что у инфляции накладные расходы на обработку ресурса макета при построении представлений.

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

Если вы хотите выполнить тесты самостоятельно, исходный код примера проекта можно найти в моем GitHub.

Каковы накладные расходы при использовании Kotlin?

Из части 1 был подвешенный вопрос о требованиях к размеру для использования Kotlin в Android. Для Kotlin есть среда выполнения и стандартная библиотека, которую вы объявляете как зависимость компиляции. Каждый раз, когда вы добавляете зависимость к Android-приложению, вам обязательно нужно учитывать ее размер, особенно если вы не можете мультииндексировать свое приложение.

В Kotlin версии 1.0.0 размер jar-файлов среды выполнения + stdlib составляет 210 КБ + 636 КБ = 846 КБ, что довольно много для библиотеки. Подсчет всех методов с использованием dex-method-counts показывает в общей сложности 6584 метода в пакете kotlin, не считая методов в среде выполнения Java, на которую он также ссылается. Это как минимум полные 10% бюджета подсчета методов для одного dex! Но после применения ProGuard в моем тестовом проекте это число упало до 42 методов. Окончательное число, конечно, будет расширяться по отношению к другим частям Kotlin, которые использует приложение. Суть в том, что использование ProGuard в приложениях, включающих Kotlin, имеет решающее значение для того, чтобы держать его под контролем для серьезного использования.

Подводя итог:

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

Вы также можете задаться вопросом, какие еще скрытые расходы связаны с использованием Kotlin. Это правильный вопрос, и он недавно был задан в обсуждении на Reddit. Я добавляю свои два цента к этому обсуждению, так что отправляйтесь туда, если хотите узнать, что некоторые люди думают по этому поводу.

Если вы хотите увидеть мой тестовый проект и сравнить XML-макеты с представлениями, созданными Kotlin, клонируйте my kotlin-view-builder repo, чтобы легко попробовать его самостоятельно.

Надеюсь, вам понравилось читать о моем опыте работы с Kotlin для Android, как и мне самому!

Я много работаю с Android, поэтому не забудьте подписаться на меня в Medium и Twitter, чтобы получать мои новые блоги.