Расширяем узкие места Xamarin.Forms

При создании мобильных приложений возникает множество различных хотелок в духе «как было бы хорошо, если бы…» И можно подставлять пункты, которые требуют улучшения. У начинающих разработчиков в этот список с высокой вероятностью войдет и пункт «если бы работало быстрее…» В данной статье будут собраны рекомендации, которые помогут начинающим разработчикам Xamarin.Forms обойти узкие места фреймворка и инструментов сборки. А начнем мы с железа.

cg9hourtlmzdlzok6fwfbp0uzko.jpeg

Передаю слово автору.

1. Настройка окружения
Первое, с чем сталкиваются разработчики Xamarin.Forms — длительная сборка проектов, гораздо дольше комфортного уровня. Это связано с тем, что при сборке создается и обновляется большое количество файлов.

_dx-4lyweyaj4isbffaiklg7smi.png

Чтобы ускорить сборку, достаточно перенести папку с исходными кодам на RAM-диск. Это когда часть оперативной памяти используется в качестве локального диска или папки в файловой системе Mac«а. Чтобы ничего не терялось, данные с RAM-диска сохраняются на SSD по таймеру. Если у вас все еще стоит обычный жесткий диск (HDD), то стоит обязательно обновиться на SSD. RAM-диск 4 ГБ + хороший SSD заметно ускоряют сборку. Примерно на порядок.


В сети вы можете найти различные утилиты для работы с RAM-дисками, а также инструкции по работе с ними.

2. Узкие места Xamarin

Как и при работе с любым другим инструментом, стоит понимать особенности Xamarin.Forms при создании приложений. Если задача приложения удивить пользователя большим количеством анимаций и нестандартным интерфейсом, то кроссплатформенные фреймворки — не лучший выбор. А вот для относительно статических бизнес-приложений они подойдут гораздо лучше.


Так как Xamarin.Forms это надстройка над классическими Xamarin.iOS и Xamarin.Android, то стоит понимать их узкие места. Ниже представлена архитектура приложения на Xamarin.iOS и Xamarin.Android.

xhvqc22jdav2kramcjgxaqwle5k.png

Xamarin-приложение состоит из двух частей: нативной и кроссплатформенной (среда Mono). Эти части общаются друг с другом через специальный мост (bridge). Вокруг каждого нативного класса и типа создается обертка для окружения Mono. При передаче данных и вызове методов в переходе «нативный»-«кроссплатформенный» происходит небольшое падение производительности, поэтому стоит обязательно это учитывать.


Например, при вычислениях и работе с данными использовать типы и классы из окружение Mono (C#/.NET), а не нативные (nfloat). Также следуем минимизировать управление UI из C#-кода. Например, не осуществлять анимации или интенсивно обновлять UI в цикле из кроссплатформенной части. Не то, чтобы были какие-то тормоза, но при больших вычислениях и массивном управлении UI (большое количество элементов с асинхронно приходящими данными и различные анимации) могут быть заметные пользователю и ненужные задержки.


В полной мере это относится и к Xamarin.Forms, который решает непростую задачу предоставить одновременно гибкий и высокопроизводительный слой работы с пользовательским интерфейсом и платформенной функциональностью для iOS, Android (а также Windows UWP, mac OS, GTK# и Tizen до кучи, но их в расчет не берем). И несмотря на то, что большинство «детских» болезней уже преодолено, в нем все еще остаются узкие места, которые следует обязательно учитывать при разработке.


3. XAML

В первых версиях Xamarin.Forms были явные проблемы с производительностью XAML-страниц. Можно было описать тот же пользовательский интерфейс на C#-коде — это уменьшало время создания (вызов конструктора!) Page или View более чем на 300 мс на устройствах средней производительности. Для сложных компонентов это время было еще больше. Свою лепту в увеличение времени холодного запуска приложения вносил App.xaml. Если в нем было много стилей и других ресурсов, то запуск приложения мог увеличиться на заметные секунды. Опять же на пустом месте. Особенно эта проблема была актуальна для Android, где простой уход от использования App.xaml и стартовых Page (например, MainPage.xaml и MenuPage.xaml) в пользу C#-кода сокращал время запуска приложения иногда в два раза.


Добавление компиляции XAML заметно уменьшило это время. В Xamarin.Forms 2.5.0 получились такие показатели для страницы Hello World:


  • XAML без компиляции 441 мс
  • XAML с компиляцией 188 мс
  • Код на C# 182 мс.


na8bkfqfhe_k-azblumiiboewha.png

Как видим, в каких-то редких случаях, например для ячеек ListView, где важна максимальная производительность, можно использовать описание интерфейса на C#. А для всех остальных сценариев можно заметно ускорить работу UI за счет добавления строки [assembly: XamlCompilation(XamlCompilationOptions.Compile)] в код вашего проекта.

rabdqkwqfvfr4tvegcgfhgkczfe.png

Также стоит учитывать, что для вложенных XAML (XAML-страница использует внешние View, также описанные за XAML) со сложной версткой и большим количеством элементов время инициализации будет выше приведенного примера Hello World. Компиляция XAML может заметно ускорить создание Page и View, а мы переходим к следующему пункту.


4. Layout

Чтобы обеспечить кроссплатформенную верстку пользовательского интерфейса для iOS, Android (и других платформ) в Xamarin.Forms реализованы свои механизмы компоновки (Layout) интерфейсных элементов. В нативном iOS и Android есть свои механизмы Layout, но они не подходят напрямую для кроссплатформенных приложений, так как имеют специфичную для каждой платформы логику.

gphc3_asmh0k10jwimvdvks52uy.png

Чтобы правильно скомпоновать страницы, фреймворк должен знать размеры вложенных на страницу элементов, а это запускает обход всего дерева дочерних контролов. В будущих релизах Xamarin.Forms обещают множество оптимизаций в том числе механизмах Layout. Но в настоящее время стоит помнить о простом правиле — чем больше точных цифр будет указано у UI-элементов и чем меньше будет уровень вложенности, тем быстрее будет отрабатывать компоновка. Например, можно указать AbsoluteLayout.LayoutBounds="0.1,0.1,0.3,0.3" или WidthRequest=”300” в свойствах UI-элемента.


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

Подробнее про оптимизацию Layout:


https://developer.xamarin.com/guides/xamarin-forms/deployment-testing/performance/#optimizelayout

Подробнее про создание своих Layout:


https://developer.xamarin.com/guides/xamarin-forms/creating-mobile-apps-xamarin-forms/summaries/chapter26/

5. Обновление UI и правильные ViewModel

Еще одной болью всех UI-подсистем, включая Xamarin.Forms, является пересчет размеров при обновлении данных. Это пресловутая проблема обновления дерева визуальных объектов, для решения которой в Web-разработке и появился ReactJS с аналогами. В mobile эта проблема есть, хотя и не такая острая.


В Xamarin.Forms используется архитектура MVVM, в которой при обновлении свойства ViewModel вызывается событие PropertyChanged, новые данные приходят в UI и View может запросить пересчет размеров и координат у всей страницы целиком.

rkcoasbf1zvgl9r1_cfuve8gura.png

Если вы обновляете 10 разных полей, то произойдет 10 циклов компоновки по всему дереву элементов на странице, а это заметные глазу пользователя 10 циклов. Для того, чтобы вместо 10 циклов запускать 1, следует использовать 1 модель с нужными 10 полями. Теперь модель и View будут обновляться целиком — одно событие PropertyChanged вместо 10.

sp0xmdwpmpj92ujjxnbozedfcsc.png

Итак, в нашей сегодняшней статье мы рассмотрели основные узкие места Xamarin.Forms и подходы, которые нивелируют их эффект. И это еще не все на сегодня!


Приглашение на Xamarin Day

Если у вас есть вопросы по Xamarin, и вам интересна разработка кроссплатформенных приложений, то напоминаю о предстоящем Xamarin Day, который пройдет 31 января в Москве. На нем вы сможете не только узнать о best practices, но и получить живую консультацию по вашему коду! Показываете куски вашего кода, по которым у вас есть вопросы (проблемы, баги, архитектура, низкая производительность и т.д.) и получаете бесплатную консультацию от экспертов прямо на месте. Чтобы подать заявку на индивидуальную консультацию по вашему проекту — напишите краткую информацию о нем и проблеме на events-techdays@microsoft.com.

Подробнее о мероприятии здесь.

Вступайте в наш уютный чат Xamarin Developers в Telegram.

Оставайтесь на связи и обязательно приходите на Xamarin Day!

Об авторе


f70e9ce7a2bd45a98e19652a08b15e26.JPGВячеслав Черников — руководитель отдела разработки компании Binwell, Microsoft MVP и Xamarin Certified Developer. В прошлом — один из Nokia Champion и Qt Certified Specialist, в настоящее время — специалист по платформам Xamarin и Azure. В сферу mobile пришел в 2005 году, с 2008 года занимается разработкой мобильных приложений: начинал с Symbian, Maemo, Meego, Windows Mobile, потом перешел на iOS, Android и Windows Phone. Статьи Вячеслава вы также можете прочитать в блоге на Medium.

Другие статьи автора вы можете найти в нашей колонке #xamarincolumn.

© Habrahabr.ru