Часть 5 – Практические стратегии совместного использования кода

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

Уровень данных

Уровень данных состоит из подсистемы хранилища и методов для чтения и записи информации. Для производительности, гибкости и кроссплатформенной совместимости СУБД SQLite рекомендуется для кроссплатформенных приложений Xamarin. Он работает на разных платформах, включая Windows, Android, iOS и Mac.

SQLite

SQLite реализовано в виде ПО с открытым исходным кодом. Источник и документации можно найти на SQLite.org. SQLite поддержка доступна на каждой мобильной платформе:

Даже у СУБД доступной на всех платформах, нативные методы доступа к базе данных различны. iOS и Android предлагают встроенные API для доступа к SQLite, которые могут быть использованы Xamarin.iOS или Xamarin.Android. Однако использование встроенных методов SDK не позволяет совместно использовать код (кроме, возможно, SQL-запросов, предполагая, что они хранятся в виде строк). Для получения дополнительной информации о нативном функционале использования SQLite следует искать в CoreData для iOS или в классе SQLiteOpenHelper для Android; Поскольку эти функции не являются кроссплатформенными, они выходят за рамки настоящего документа.

ADO.NET

Xamarin.iOS и Xamarin.Android поддерживают System.Data и Mono.Data.Sqlite (см. Xamarin.iOS документацию для получения дополнительной информации). Использование этих пространств имен позволяет писать код ADO.NET, который работает на обеих платформах. Для использования нужно добавить System.Data.dll и Mono.Data.Sqlite.dll в ссылки проекта и в код с помощью оператора using:

Тогда следующий пример кода будет работать:

Реальные реализации ADO.NET, очевидно, будут разделены между различными методами и классами (этот пример для демонстрационных целей).

SQLite-NET – Кроссплатформенный ORM

ORM (или Object-Relational Mapper) позволяет упростить хранение данных, смоделированных в классах. Вместо того, что бы писать вручную SQL-запросы, создания таблиц или выборки, вставки и удаления данных, которые вручную извлечены из полей и свойств класса, ORM добавляет слой кода, который делает это за вас. Использую рефлексию при исследовании структуры классов, ORM может автоматически создавать таблицы и столбцы, которые соответствуют классу и создавать запросы для чтения и записи данных. Это позволяет коду приложения просто отправлять и получать экземпляры объектов к ORM, который заботится о всех SQL-операциях.

SQLite-NET действует как простой ORM, который позволит вам сохранить и восстановить свои классы в SQLite. Он скрывает сложность кроссплатформенного доступа к SQLite при совмещении директив компилятора и других хитростей.

Особенности SQLite-NET:

  • Таблицы определяются путем добавления атрибутов моделей классов.
  • Экземпляр базы данных представлен подклассом SQLiteConnection, основного класса в SQLite-Net библиотеке.
  • Данные могут быть вставлены, запрошены и удалены, используя объекты. Никаких SQL-запросов не требуется (хотя вы можете написать SQL-запросы в случае необходимости).
  • Основные Linq-запросы могут быть выполнены на коллекциях возвращенных SQLite-NET.

Исходный код и документация SQLite-NET доступна на SQLite-Net на GitHub и был реализован в обоих тематических исследованиях. Простой пример кода SQLite-NET (на примере Tasky Pro) приведены ниже.

Во-первых класс TodoItem использует атрибуты для определения полей для первичного ключа базы данных:

Это позволяет создать таблицу TodoItem с помощью следующей строки кода (и без каких-либо SQL-запросов) на экземпляре SQLiteConnection:

Данными в таблице также можно манипулировать использую другие методы на SQLiteConnection (опять же, не требуя SQL-запросов):

Доступ к файлам

Доступ к файлам, несомненно, будет ключевой частью любого приложения. Типичные примеры файлов, которые могут быть частью приложения:

  • Файлы базы данных SQLite.
  • Данные созданные пользователем (техт, изображения, аудио- и видео-файлы).
  • Загруженные данные для кэширования (изображения, html или PDF файлы).

System.IO Прямой доступ

Xamarin.iOS и Xamarin.Android разрешают доступ к файловой системе с помощью классов в пространстве имен System.IO.

Каждая платформа имеет ограничения доступа, которые должны быть приняты во внимание:

  • iOS приложения выполняются в изолированной программной среде с очень ограниченным доступом к файловой системе. Apple также диктует, как вы должны использовать файловую систему, указав определенные места, которые являются резервными (и другие, которые таковыми не являются). Обратитесь к руководству Работа с файловой системой в Xamarin.iOS  для получения более подробной информации.
  • Android также ограничивает доступ к некоторым каталогам, относящиеся к приложению, но он поддерживает внешние носители (например, SD карты) и доступ к общим данным.
  • Windows Phone 8 (Silverlight) не допускает прямого доступа к файлам – файлами можно манипулировать только с помощью IsolatedStorage.
  • Проекты Windows 8.1 WinRT и Windows 10 UWP предлагают только асинхронные файловые операции через Windows.Storage, которые отличаются от других платформ.

Примеры для iOS и Android

Ниже показан тривиальный пример, который пишет и читает текстовый файл. Использование Environment.GetFolderPath позволяет один и тот же код использовать в iOS и Android, которые возвращают действительный каталог на основе соглашений их файловой системы.

Обратитесь к документации Xamarin.iOS Работа с файловой системой для получения дополнительной информации о функциях iOS-специфичной файловой системы. При написании кроссплатформенного кода доступа к файлам, помните, что некоторые файловые системы учетываюь регистр символов и имеют разные разделители каталогов. Рекомендуется всегда использовать один регистр для имен файлов и метод Path.Combine() при построении пути к файлу или каталогу.

Windows.Storage в Windows 8 и Windows 10

В книге по создании мобильных приложения с Xamarin.Forms Глава 20. Асинхронный и файловый ввод/вывод  (Async and File I/O) включает в себя примеры для ОС Windows 8.1 и Windows 10.

Используя DependencyService можно читать и писать файлы на этих платформах, используя поддерживаемые API-интерфейсы:

Изолированное хранилище в Windows Phone 7 и 8 (Silverlight)

Изолированное хранилище (Isolated Storage) — общий API для сохранения и загрузки файлов во всех iOS, Android и старых платформах Windows Phone.

Это механизм по умолчанию для доступа к файлам в Windows Phone (Silverlight), который был реализован в Xamarin.iOS и Xamarin.Android, для обеспечения общего кода доступа к файлам для записи. На класс System.IO.IsolatedStorage можно ссылаться во всех трех платформах, в Shared Project.

См. Обзор Изолированного хранилища (Isolated Storage) для Windows Phone для получения дополнительной информации.

API интерфейсы Isolated Storage недоступны в Portable Class Libraries. Единственной альтернативой для PCL является PCLStorage NuGet

Кроссплатформенный доступ к файлам в PCL

Существует также PCL-совместимый кроссплатформенный Nuget компонент доступа к файлам — PCLStorage для платформ, поддерживаемых Xamarin и новейшими Windows API.

Примеры кода доступны на странице соответствующих компонентов.

Сетевые операции

Большинству мобильных приложений необходимо иметь сетевой компонент, например:

  • Загрузка изображений, видео и аудио (например, эскизы, фотографии, музыка).
  • Загрузка  документов (например, HTML, PDF).
  • Загрузка данных пользователя (например, фотографии или текст).
  • Доступ к веб-службам или API-интерфейсам сторонних разработчиков  (включая SOAP, XML или JSON).

Платформа .NET Framework предоставляет несколько различных классов для доступа к сетевым ресурсам: HttpClient, WebClient, и HttpWebRequest.

HttpClient

Класс HttpClient в пространстве имен System.Net.Http доступен в Xamarin.iOS, Xamarin.Android и большинстве платформ Windows. Существует Microsoft HTTP Client Library Nuget, который может быть использован, чтобы принести этот API в PCL и Windows Phone 8 Silverlight.

WebClient

Класс WebClient предоставляет простой API для получения данных с удаленных серверов.

Операции Universal Windows Platofrm (UWP) должны быть обязательно асинхронными, а Xamarin.iOS и Xamarin.Android поддерживают только синхронные операции (которые могут быть сделаны в фоновых потоках).

Код для простой асинхронной операции WebClient:

WebClient также имеет DownloadFileCompleted и DownloadFileAsync для получения двоичных данных.

HttpWebRequest

HttpWebRequest предлагает больше настроек, чем WebClient и в результате требует большего количества кода для использования.

Код для простой синхронной операции HttpWebRequest:

Доступность

Мобильные устройства работают в различных условиях сети от быстрого Wi-Fi или 4G подключения до районов с плохим приемом и медленных подключений  EDGE. Поэтому хорошая практика, для начала определить, доступна ли сеть и если да, какой тип сети доступен, прежде чем подключаться к удаленным серверам.

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

  • Если сеть недоступна, сообщите об этом пользователю. Если он вручную отключил её (например, включен Режим полета или выключен Wi-Fi), то пользователи смогут решить эту проблему.
  • Если имеется соединение 3G, то приложения могут вести себя по-разному (например, Apple не поддерживает в приложениях загрузки через 3G больше 20Mb данных). Приложения могут использовать эту информацию, чтобы предупредить пользователя о чрезмерном времени загрузки при получении больших файлов.
  • Даже если сеть доступна, то хорошей практикой будет  проверка соединения с целевым сервером перед запуском других запросов. Это предотвратит неоднократные сетевые операции приложения с истечением времени ожидания  и также позволят отображать для пользователя более информативное сообщение об ошибке.

Здесь пример кода Xamarin.iOS (который основан на примере доступности от Apple), чтобы помочь обнаружить доступность сети.

Веб-сервисы

Смотрите нашу документацию по Работе с веб-службами, которая охватывает доступ к REST, SOAP и WCF конечных точек с помощью Xamarin.iOS. Можно вручную создавать кустарные запросы к веб-сервисам и анализировать ответы, однако есть доступные библиотеки, чтобы сделать это намного проще, в том числе Azure, RestSharp и ServiceStack. Даже базовые операции WCF доступны в Xamarin приложениях.

Azure

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

Посетите azure.microsoft.com, чтобы попробовать его бесплатно и включите компонент Azure, чтобы начать работу.

RestSharp

RestSharp — библиотека .NET, которые могут быть включены в мобильные приложения клиента REST, который упрощает доступ к веб-службам. Она помогает, предоставляя простой API для запроса данных и проанализировать ответ REST. RestSharp может быть полезным.

Сайт RestSharp содержит документацию о том, как реализовать клиента REST с помощью RestSharp. RestSharp предоставляет примеры для Xamarin.iOS и Xamarin.Android на GitHub.

 Существует также фрагмент кода Xamarin.iOS в нашей документации веб-служб.

ServiceStack

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

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

Существует пример Xamarin.iOS на сайте ServiceStack, и фрагмент кода в нашей документации веб-служб.

WCF

Xamarin инструменты могут помочь вам использовать некоторые службы Windows Communication Foundation (WCF). В общем Xamarin поддерживает то же подмножество на стороне клиента WCF, который поставляется вместе со средой выполнения Silverlight. Это включает в себя наиболее распространенные реализации кодирования и протокола WCF: текст в кодировке сообщения SOAP через транспортный протокол HTTP  с использованием BasicHttpBinding.

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

Многопоточность

Скорость реакции приложений имеет важное значение для мобильных приложений – пользователи ожидают, что приложения будут быстро и загружаться, и выполняться. А если появляется «замороженный» экран, который прекращает принимать входные данные пользователя, то это указывает на то, что в приложении произошёл сбой, поэтому очень важно не объединять поток пользовательского интерфейса с длительной блокировки вызовов, например сетевыми запросами или медленными локальными операциями (например, разархивирования файла). Также процесс запуска не должен содержать долго выполняющихся задач – все мобильные платформы будут убивать приложение, которое занимает слишком много времени для загрузки.

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

Библиотека параллельных задач (Parallel Task Library)

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

Простая задача параллельной операции может выглядеть следующим образом:

Ключ TaskScheduler.FromCurrentSynchronizationContext который будет повторно использовать SynchronizationContext.Current трэды, вызывающий метод (это основной поток, тот который работает — MainThreadMethod) как способ управления обратными вызовами на этот поток. То есть, если метод вызывается в потоке пользовательского интерфейса, он будет обрабатывать операцию ContinueWith с возвращением управления обратно в поток пользовательского интерфейса.

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

Вызов потока пользовательского интерфейса

Для кода, который не использует Parallel Task Library, каждая платформа имеет свой собственный синтаксис для возврата управления в поток пользовательского интерфейса:

  • iOSowner.BeginInvokeOnMainThread(new NSAction(action))
  • Androidowner.RunOnUiThread(action)
  • Xamarin.FormsDevice.BeginInvokeOnMainThread(action)
  • WindowsDeployment.Current.Dispatcher.BeginInvoke(action)

И iOS, и Android синтаксис требуют доступный класс «контекста», чтобы код мог передать этот объект в любые методы, которые требуют обратного вызова в поток пользовательского интерфейса.

Для того, чтобы реализовать вызовы потока пользовательского интерфейса в общем коде, следуйте примеру IDispatchOnUIThread (любезно предоставлено @follesoe). Создайте интерфейс IDispatchOnUIThread в совместно используемом коде, а затем реализуйте классы специфичные для платформы, как показано здесь:

Xamarin.Forms разработчики должны использовать Device.BeginInvokeOnMainThread в общем коде (Shared Projects или PCL).


Оригинал статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *