company_banner

Готовим Xamarin.Forms: настройка окружения и первые шаги



    Друзья! Мы продолжаем колонку на тему разработки мобильных приложений на Xamarin. И
    после небольшого перерыва готовы вернуться к рассмотрению особенностей использования Xamarin.Forms при разработке бизнес-приложений для iOS и Android. Все статьи из колонки можно будет найти и прочитать по ссылке #xamarincolumn

    В сегодняшней статье мы рассмотрим вопросы производительности приложений и оптимизации самого процесса разработки.

    Правильные пчелы


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

    Начнем мы с компьютеров, на которых будет идти разработка.

    В своей практике в качестве основной среды мы используем Windows 10 и Visual Studio 2015, поэтому столкнулись с тем, что сборка приложений (в первую очередь Android) занимает непозволительно долго времени.

    Мы стали выяснять в чем здесь дело и выявили несколько узких мест, замедляющих разработку:
    • во время сборки Android-приложений Xamarin может в первый раз выкачивать необходимые исходные коды дополнительных компонентов и складывать их на локальный диск для последующего использования. Здесь ничего поделать нельзя, поэтому просто будьте готовы к тому, что первая сборка может занять у вас минут 10.
    • дальше начинается самое интересное: во время сборки Xamarin гененерирует и использует большое количество файлов (до 200 МБ в папках bin и obj, плюс еще целая куча в папке Temp), поэтому сразу забудьте про использование жестких дисков (HDD) на рабочих станциях — чем быстрее будет у вас SSD, тем лучше.

    Особо продвинутым можно рекомендовать использование ОЗУ в качестве раздела для хранения проектов и системной Temp-папки — для этого нужно использовать одну из программ класса RAM Disk.Точных измерений при использовании SSD+RAM Disk не производили, но на глаз разница колоссальна.

    Итак, считаем, что с правильным окружением мы разобрались.

    XAML — зло или благо


    Одним из важных механизмов Xamarin.Forms является возможность использования XAML (на базе XML) для описания интерфейса пользователей.

    На наш взгляд, это является хорошим решением с точки зрения технологии производства, так как происходит отделение логики от описания интерфейса и сама по себе UI-разработка становится очень похожей на HTML-верстку, даже стили контролов можно задавать в одном месте как с CSS (ликбез по стилям по ссылке), включая небольшой тюнинг для разных платформ (Device.OnPlatform).

    Все было бы отлично, если бы не одно большое “НО”, которое характерно для Xamarin.Forms версии 1.х — XAML-файлы интерпретировались на лету, включая создание всех необходимых контролов и их размещение на экране. Из-за этого каждое открытие нового окна со сложной компоновкой происходило дольше, чем хотелось бы.

    В версии 2.0 этот недостаток устранили, реализовав предварительную компиляцию XAML. Использовать ее можно как для отдельных страниц и View на XAML, так и для всего проекта целиком.

    Включаем компиляцию отдельной XAML-страницы (файл MainPage.xaml.cs, например)



    using Xamarin.Forms.Xaml;
    ...
    [XamlCompilation (XamlCompilationOptions.Compile)]
    public class MainPage : ContentPage
    { 
    ...
    }
    


    Активируем компиляцию по всему проекту — добавляем новую строку в конец файла Properties/AssemblyInfo.cs в PCL-проекте:



    ...
    [assembly: XamlCompilation(XamlCompilationOptions.Compile)]
    


    Однако в некоторых случаях, особенно при реализации ячеек для ListView, может быть эффективнее описать компоновку для ViewCell/View/Page руками в коде на C# или спуститься на уровень iOS/Android.



    Но к ListView мы еще вернемся.



    Картинки, иконки и производительность


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

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

    Стандартный компонент для отображения Image хорош, даже поддерживает кеширование, но он мало пригоден при использовании в реальных проектах. Когда год назад мы уперлись в ограничения Image, пришлось сделать свой простенький кешер изображений с автоматическим масштабированием — для отображения в ячейку передавалась уменьшенная версия, так как с большими изображениями списки просто умирали (это не проблема Xamarin.Forms, а вообще любой разработки приложений, но на Xamarin.Forms она была очень острой).

    Потом мы перепробовали несколько различных библиотек и в конце концов остановились на превосходном компоненте под названием FFImageLoading.



    Он доступен в Nuget () и позволяет решить сразу несколько задач:


    • фоновая загрузку изображений с возможностью повтора запросов;
    • использование placeholder во время загрузки;
    • автоматическое масштабирование изображений до размеров контрола, включая удаление Alpha-канала на Android для еще большей производительности;
    • возможность применения трансформаций к изображениям после загрузки (обрезать до круга или другой формы, наложить blur или другой спец. эффект);
    • fade-анимация появления изображения после загрузки.

    Вот так использовать компонент при разработке на XAML:



    <?xml version="1.0" encoding="UTF-8"?>
    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
      x:Class="Sample.Pages.MainPage"
        xmlns:ffimageloading="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms"
        Title="FFImageLoading Demo">
        <ContentPage.Content>
            <ffimageloading:CachedImage HorizontalOptions="Center" VerticalOptions="Center"
                WidthRequest="300" HeightRequest="300"
                DownsampleToViewSize="true"
                Source = "https://unsplash.it/600/600/?random"
    		LoadingPlaceholder = "placeholder.png">
            </ffimageloading:CachedImage>
       </ContentPage.Content>
    </ContentPage>
    

    Вот так можно еще немного улучшить работу FFImageLoading (класс AppDelegate.cs для iOS и MainActivity.cs для Android):



    var config = new Configuration
                {
                    HttpClient = new HttpClient(new ModernHttpClient.NativeMessageHandler()),  //используем быстрые библиотеки для загрузки
                    FadeAnimationDuration = 250,  //ускоряем анимацию появления
                };
    FFImageLoading.ImageService.Instance.Initialize(config);
    

    Работаем со спискам в Xamarin.Forms


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

    Первая рекомендация касается механизмов работы ListView. В ранних версиях Xamarin.Forms не поддерживался механизм повторного использования созданных ячеек, что приводило к созданию экземпляров ViewCell каждый раз при необходимости их отображения — это и было первой серьезной причиной залипаний при скроле.

    В последних версиях Xamarin.Forms реализован механизм повторного использования созданных ячеек и для его активации необходимо задать свойству CachingStrategy значение ListViewCachingStrategy.RecycleElement.

    Реализация в XAML:


    <ListView CachingStrategy="RecycleElement">
    	...
    </ListView>
    

    Реализация на C#:


    var listView = new ListView(ListViewCachingStrategy.RecycleElement);
    


    После этого созданные экземпляры ViewCell начинают использоваться повторно и к ним просто подключаются (через Binding) необходимые модели данных по мере отображения.



    Еще один интересный способ подсказал мой коллега Кирилл — просто останавливать загрузку и отображение картинок во время прокрутки списка. Этот способ также рекомендуют использовать и создатели FFImageLoading.

    Для этого необходимо сделать свой рендерер для ListView для каждой платформы и переопределить события прокрутки.

    Пример для Android:


    _listView.ScrollStateChanged += (object sender, ScrollStateChangedEventArgs scrollArgs) => {
      switch (scrollArgs.ScrollState)
      {
      case ScrollState.Fling:
          ImageService.Instance.SetPauseWork(true); // ставим загрузку картинок на паузу 
          break; 
          case ScrollState.Idle: 
          ImageService.Instance.SetPauseWork(false); // возобновляем загрузку картинок 
         // здесь должен быть ваш код отображения изображений в отображаемых ячейках 
          ShowMyImage();      
          break;</p>
       } 
     }; 
    


    При необходимости вы также можете создать свои реализации ViewCell через механизм Custom Renderer для каждой платформы — такой подход может быть актуален для сложных ячеек с большим количеством встроенных контролов.



    Также хорошие результаты при работе с большими объемами данных и сложными ячейками позволяет достичь использование нативных компонентов UICollectionView (для iOS) и RecyclerView (для Android), но это решение можно рекомендовать продвинутым разработчикам.

    Пример использования данных классов представлен в библиотеке TwinTechs — обязательно к знакомству, так как там есть видео-ролики с результатами оптимизации.

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



    Заключение


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

    В следующем материале мы расскажем об использовании иконочных шрифтов в стиле Font Awesome, инструмента Fody для сокращения кода у ViewModel и механизмах ручной отрисовки своих интерфейсных элементов с помощью библиотеки NControlView.

    Оставайтесь на связи и добавляйте свои комментарии и вопросы!

    Об авторах



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

    Другие статьи автора:


    Полезные ссылки


    Microsoft
    Microsoft — мировой лидер в области ПО и ИТ-услуг

    Similar posts

    Comments 8

      +2
      Подводя итог, XF все еще хорош только для опытных ксамаринщиков, которые понимают нативные дебри целевых платформ.
      Как можно не включить переиспользование ячеек по-умолчанию?

      Но такими темпами, к третьей версии может получиться неплохой кросс-платформенный фреймворк для новичков.
        0
        > И после небольшого перерыва готовы вернуться к рассмотрению особенностей использования Xamarin.Forms при разработке бизнес-приложений для iOS и Android.
        > Начнем мы с компьютеров, на которых будет идти разработка.
        > В своей практике в качестве основной среды мы используем Windows 10 и Visual Studio 2015

        А как в вашей практике происходит сборка под iOS? Нужна Mac OS или есть какие-то другие пути?
          0
          MacOS все ещё нужна.

          Хотя VS 2015 вроде научилась собирать девелоперские сборки Obj-C iOS приложений, до Xamarin такое счастье ещё не добралось.
          0
          Забавно как проект идёт по темже граблям, по которым прошёл FireMonkey
            0
            Мне прям интересно, на какие? с учетом того, что FM рисуют интерфейс сами а XF используют нативные компоненты?
              0
              Тормоза скроллинга и те причины что их вызывают.
              А в FMX на iOS и Windows некоторые компоненты уже имеют нативное представление.
                0
                Тормоза скроллинга и те причины что их вызывают.

                На эти грабли и android наступил. RecyclerView с принудительной виртуализацией появилось только в Android L.
            0
            Активируем компиляцию по всему проекту — добавляем новую строку в конец файла Properties/AssemblyInfo.cs в PCL-проекте:


            [assembly: XamlCompilation(XamlCompilationOptions.Compile)]

            Однако в некоторых случаях, особенно при реализации ячеек для ListView, может быть эффективнее описать компоновку для ViewCell/View/Page руками в коде на C# или спуститься на уровень iOS/Android.

            Простите, не могли бы вы пояснить, не совсем понял. Как я понял, XamlCompilation атрибут ускоряет загрузку xaml-cтраниц в студии. Как это соотносится с ViewCell c C#?

            Only users with full accounts can post comments. Log in, please.