Часть 5. Практические стратегии совместного использования кода
В этом разделе приведены примеры совместного использования кода для распространенных сценариев приложения.
Уровень данных
Уровень данных состоит из подсистемы хранилища и методов для чтения и записи информации. Для обеспечения производительности, гибкости и кроссплатформенной совместимости ядра СУБД SQLite рекомендуется использовать для кроссплатформенных приложений Xamarin. Он работает на различных платформах, включая Windows, Android, iOS и Mac.
SQLite
SQLite — это реализация базы данных с открытым кодом. Источник и документация можно найти по адресу SQLite.org. Поддержка SQLite доступна на каждой мобильной платформе:
- iOS — встроенный в операционную систему.
- Android — встроенный в операционную систему с Android 2.2 (уровень API 10).
- Windows — см. расширение SQLite для универсальная платформа Windows.
Даже если ядро СУБД доступно на всех платформах, собственные методы для доступа к базе данных отличаются. Как iOS, так и Android предлагают встроенные API-интерфейсы для доступа к SQLite, которые можно использовать из Xamarin.iOS или Xamarin.Android, однако использование собственных методов SDK не обеспечивает возможности совместного использования кода (кроме, возможно, сами запросы SQL, предполагая, что они хранятся в виде строк). Дополнительные сведения о функциях собственной базы данных для поиска CoreData
в классе iOS или Android SQLiteOpenHelper
, так как эти параметры не являются кроссплатформенными, они выходят за рамки этого документа.
ADO.NET
Поддержка System.Data
Xamarin.iOS и Xamarin.Android и Mono.Data.Sqlite
(дополнительные сведения см. в документации по Xamarin.iOS).
С помощью этих пространств имен можно создавать ADO.NET код, который работает на обеих платформах. Измените ссылки проекта, чтобы включить System.Data.dll
и Mono.Data.Sqlite.dll
добавить эти инструкции using в код:
using System.Data;
using Mono.Data.Sqlite;
Затем будет работать следующий пример кода:
string dbPath = Path.Combine (
Environment.GetFolderPath (Environment.SpecialFolder.Personal),
"items.db3");
bool exists = File.Exists (dbPath);
if (!exists)
SqliteConnection.CreateFile (dbPath);
var connection = new SqliteConnection ("Data Source=" + dbPath);
connection.Open ();
if (!exists) {
// This is the first time the app has run and/or that we need the DB.
// Copy a "template" DB from your assets, or programmatically create one like this:
var commands = new[]{
"CREATE TABLE [Items] (Key ntext, Value ntext);",
"INSERT INTO [Items] ([Key], [Value]) VALUES ('sample', 'text')"
};
foreach (var command in commands) {
using (var c = connection.CreateCommand ()) {
c.CommandText = command;
c.ExecuteNonQuery ();
}
}
}
// use `connection`... here, we'll just append the contents to a TextView
using (var contents = connection.CreateCommand ()) {
contents.CommandText = "SELECT [Key], [Value] from [Items]";
var r = contents.ExecuteReader ();
while (r.Read ())
Console.Write("\n\tKey={0}; Value={1}",
r ["Key"].ToString (),
r ["Value"].ToString ());
}
connection.Close ();
Реальные реализации ADO.NET, очевидно, будут разделены по разным методам и классам (этот пример предназначен только для демонстрационных целей).
SQLite-NET — кроссплатформенный ORM
ORM (или объектно-реляционный mapper) пытается упростить хранение данных, моделироваемых в классах. Вместо того, чтобы вручную писать запросы SQL, которые СОЗДАЮТ ТАБУЛЫ или SELECT, INSERT и DELETE данные, извлеченные вручную из полей и свойств класса, ORM добавляет слой кода, который делает это для вас. С помощью отражения для изучения структуры классов ORM может автоматически создавать таблицы и столбцы, которые соответствуют классу и создают запросы для чтения и записи данных. Это позволяет коду приложения просто отправлять и извлекать экземпляры объектов в ORM, который заботится обо всех операциях SQL под капюшоном.
SQLite-NET выступает в качестве простого ORM, который позволяет сохранять и извлекать классы в SQLite. Она скрывает сложность кроссплатформенного доступа SQLite с сочетанием директив компилятора и других трюков.
Функции SQLite-NET:
- Таблицы определяются путем добавления атрибутов в классы Model.
- Экземпляр базы данных представлен подклассом основного
SQLiteConnection
класса в библиотеке SQLite-Net. - Данные можно вставлять, запрашивать и удалять с помощью объектов. Инструкции SQL не требуются (хотя при необходимости можно написать инструкции SQL).
- Базовые запросы Linq можно выполнять в коллекциях, возвращаемых SQLite-NET.
Исходный код и документация для SQLite-NET доступна в SQLite-Net на github и реализована в обоих примерах. Ниже показан простой пример кода SQLite-NET (из примера tasky Pro ).
Во-первых, TodoItem
класс использует атрибуты для определения поля в качестве первичного ключа базы данных:
public class TodoItem : IBusinessEntity
{
public TodoItem () {}
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public string Name { get; set; }
public string Notes { get; set; }
public bool Done { get; set; }
}
Это позволяет TodoItem
создать таблицу со следующей строкой кода (и без инструкций SQL) в экземпляре SQLiteConnection
:
CreateTable<TodoItem> ();
Данные в таблице также можно управлять другими методами SQLiteConnection
(опять же, не требуя инструкций SQL):
Insert (TodoItem); // 'task' is an instance with data populated in its properties
Update (TodoItem); // Primary Key field must be populated for Update to work
Table<TodoItem>.ToList(); // returns all rows in a collection
Полные примеры см. в исходном коде примера.
Доступ к файлам
Доступ к файлам, несомненно, является ключевой частью любого приложения. Распространенные примеры файлов, которые могут быть частью приложения:
- Файлы базы данных 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
API, которые отличаются от других платформ.
Пример для iOS и Android
Ниже показан тривиальный пример записи и чтения текстового файла.
Использование Environment.GetFolderPath
позволяет выполнять тот же код в iOS и Android, которые возвращают допустимый каталог на основе соглашений файловой системы.
string filePath = Path.Combine (
Environment.GetFolderPath (Environment.SpecialFolder.Personal),
"MyFile.txt");
System.IO.File.WriteAllText (filePath, "Contents of text file");
Console.WriteLine (System.IO.File.ReadAllText (filePath));
Дополнительные сведения о функциональных возможностях файловой системы см. в документе Xamarin.iOS. При написании кроссплатформенного кода доступа к файлам помните, что некоторые файловые системы чувствительны к регистру и имеют разные разделители каталогов. Рекомендуется всегда использовать один и тот же регистр для имен файлов и Path.Combine()
метода при создании путей к файлу или каталогу.
Windows.Storage для Windows 8 и Windows 10
Книга "Создание мобильных приложений с помощью книги Xamarin.Forms" 20. Асинхронный и файловый ввод-вывод содержат примеры для Windows 8.1 и Windows 10.
DependencyService
С помощью файла и чтения файлов на этих платформах можно использовать поддерживаемые API:
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
IStorageFile storageFile = await localFolder.CreateFileAsync("MyFile.txt",
CreationCollisionOption.ReplaceExisting);
await FileIO.WriteTextAsync(storageFile, "Contents of text file");
Дополнительные сведения см. в разделе книги 20 .
Изолированное хранилище в Windows Phone 7 и 8 (Silverlight)
Изолированное хранилище — это общий API для сохранения и загрузки файлов на всех платформах iOS, Android и более старых платформ Windows Phone.
Это механизм доступа к файлам по умолчанию в Windows Phone (Silverlight), реализованный в Xamarin.iOS и Xamarin.Android, чтобы разрешить запись общего кода доступа к файлам. Класс System.IO.IsolatedStorage
можно ссылаться на все три платформы в общем проекте.
Дополнительные сведения см. в обзоре изолированного хранилища для Windows Phone .
API изолированного хранилища недоступны в переносимых библиотеках классов. Одним из вариантов для PCL является PCLStorage NuGet
Межплатформенный доступ к файлам в PCLs
Существует также PCL-совместимый NuGet ( PCLStorage ), который обеспечивает кроссплатформенный доступ к файлам для поддерживаемых Xamarin платформ и последних API Windows.
Операции сети
Большинство мобильных приложений будут иметь сетевой компонент, например:
- Скачивание изображений, видео и звука (например, эскизы, фотографии, музыка).
- Скачивание документов (например, HTML, PDF).
- Отправка данных пользователя (например, фотографий или текста).
- Доступ к веб-службам или сторонним API-интерфейсам (включая SOAP, XML или JSON).
Платформа .NET Framework предоставляет несколько различных классов для доступа к сетевым ресурсам: HttpClient
, WebClient
и HttpWebRequest
.
HttpClient
Класс HttpClient
в System.Net.Http
пространстве имен доступен в Xamarin.iOS, Xamarin.Android и большинстве платформ Windows. Существует клиентская библиотека Microsoft HTTP NuGet, которую можно использовать для переноса ЭТОГО API в переносимые библиотеки классов (и Windows Phone 8 Silverlight).
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://xamarin.com");
var response = await myClient.SendAsync(request);
WebClient
Класс WebClient
предоставляет простой API для получения удаленных данных с удаленных серверов.
универсальная платформа Windows операции должны быть асинхронными, хотя Xamarin.iOS и Xamarin.Android поддерживают синхронные операции (которые можно выполнять в фоновых потоках).
Код простой асихронной WebClient
операции:
var webClient = new WebClient ();
webClient.DownloadStringCompleted += (sender, e) =>
{
var resultString = e.Result;
// do something with downloaded string, do UI interaction on main thread
};
webClient.Encoding = System.Text.Encoding.UTF8;
webClient.DownloadStringAsync (new Uri ("http://some-server.com/file.xml"));
WebClient
также имеет DownloadFileCompleted
и DownloadFileAsync
для получения двоичных данных.
HttpWebRequest
HttpWebRequest
предлагает больше настроек, чем WebClient
и в результате требуется больше кода для использования.
Код простой синхронной HttpWebRequest
операции:
var request = HttpWebRequest.Create(@"http://some-server.com/file.xml ");
request.ContentType = "text/xml";
request.Method = "GET";
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
if (response.StatusCode != HttpStatusCode.OK)
Console.WriteLine("Error fetching data. Server returned status code: {0}", response.StatusCode);
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
var content = reader.ReadToEnd();
// do something with downloaded string, do UI interaction on main thread
}
}
В нашей документации по веб-службам приведен пример.
Возможность доступа
Мобильные устройства работают в различных условиях сети от быстрых подключений Wi-Fi или 4G к плохим зонам приема и медленным каналам данных EDGE. Из-за этого рекомендуется определить, доступна ли сеть и если да, то какой тип сети доступен, прежде чем пытаться подключиться к удаленным серверам.
Действия мобильного приложения могут выполняться в следующих ситуациях:
- Если сеть недоступна, сообщите пользователю. Если они отключили его вручную (например, если они отключили его вручную. Режим самолета или отключение Wi-Fi, затем они могут устранить проблему.
- Если подключение равно 3G, приложения могут вести себя по-разному (например, Apple не разрешает скачиванию приложений размером более 20 Мб по сравнению с 3G). Приложения могут использовать эти сведения, чтобы предупредить пользователя о чрезмерном времени загрузки при получении больших файлов.
- Даже если сеть доступна, рекомендуется проверить подключение с целевым сервером перед инициированием других запросов. Это позволит предотвратить многократное время ожидания сетевых операций приложения, а также позволит отображать пользователю более информативное сообщение об ошибке.
Веб-службы
Ознакомьтесь с нашей документацией по работе с веб-службами, которая охватывает доступ к конечным точкам REST, SOAP и WCF с помощью Xamarin.iOS. Вы можете вручную создавать запросы веб-службы и анализировать ответы, однако существуют библиотеки, которые позволяют сделать это гораздо проще, включая Azure, RestSharp и ServiceStack. Даже к основным операциям WCF можно обращаться в приложениях Xamarin.
Azure
Microsoft Azure — это облачная платформа, которая предоставляет широкий спектр служб для мобильных приложений, включая хранилище данных и синхронизацию, а также push-уведомления.
Посетите azure.microsoft.com , чтобы попробовать его бесплатно.
RestSharp
RestSharp — это библиотека .NET, которая может быть включена в мобильные приложения для предоставления клиента REST, который упрощает доступ к веб-службам. Это помогает предоставить простой API для запроса данных и анализа ответа REST. RestSharp может быть полезным
Веб-сайт RestSharp содержит документацию по реализации клиента REST с помощью RestSharp. RestSharp предоставляет примеры Xamarin.iOS и Xamarin.Android на github.
В нашей документации по веб-службам также есть фрагмент кода Xamarin.iOS.
ServiceStack
В отличие от RestSharp, ServiceStack — это серверное решение для размещения веб-службы, а также клиентской библиотеки, которая может быть реализована в мобильных приложениях для доступа к этим службам.
Веб-сайт ServiceStack объясняет назначение проекта и ссылки на примеры документов и кода. Примеры включают полную реализацию веб-службы на стороне сервера, а также различные клиентские приложения, которые могут получить к нему доступ.
WCF
Средства Xamarin помогут вам использовать некоторые службы Windows Communication Foundation (WCF). Как правило, Xamarin поддерживает тот же клиентский подмножество WCF, которое поставляется с средой выполнения Silverlight. К ним относятся наиболее распространенные реализации кодировки и протокола WCF: текстовые сообщения SOAP по протоколу транспорта HTTP с помощью BasicHttpBinding
протокола .
Из-за размера и сложности платформы WCF могут существовать текущие и будущие реализации служб, которые будут находиться за пределами области, поддерживаемой доменом подмножества клиента Xamarin. Кроме того, поддержка WCF требует использования средств, доступных только в среде Windows для создания прокси-сервера.
Потоки
Скорость реагирования приложений важна для мобильных приложений— пользователи ожидают, что приложения загружают и выполняются быстро. Экран "замороженный", который перестает принимать входные данные пользователя, будет отображаться, что приложение завершится сбоем, поэтому важно не связывать поток пользовательского интерфейса с длительными блокирующими вызовами, такими как сетевые запросы или медленные локальные операции (например, распаковка файла). В частности, процесс запуска не должен содержать длительные задачи. Все мобильные платформы убьют приложение, которое занимает слишком много времени для загрузки.
Это означает, что пользовательский интерфейс должен реализовать "индикатор хода выполнения" или иначе "удобный" пользовательский интерфейс, который быстро отображается и асинхронные задачи для выполнения фоновых операций. Выполнение фоновых задач требует использования потоков, что означает, что фоновые задачи должны быть способом обратного взаимодействия с основным потоком для указания хода выполнения или завершения.
Библиотека параллельных задач
Задачи, созданные с помощью библиотеки параллельных задач, могут выполняться асинхронно и возвращать вызововый поток, что делает их очень полезными для запуска длительных операций без блокировки пользовательского интерфейса.
Простая параллельная операция задачи может выглядеть следующим образом:
using System.Threading.Tasks;
void MainThreadMethod ()
{
Task.Factory.StartNew (() => wc.DownloadString ("http://...")).ContinueWith (
t => label.Text = t.Result, TaskScheduler.FromCurrentSynchronizationContext()
);
}
Ключ заключается в TaskScheduler.FromCurrentSynchronizationContext()
том, что будет повторно использовать синхронизациюContext.Current потока, вызывающего метод (здесь основной поток, который выполняется MainThreadMethod
) в качестве способа маршалирования обратных вызовов этого потока. Это означает, что если метод вызывается в потоке пользовательского интерфейса, он будет выполнять ContinueWith
операцию обратно в потоке пользовательского интерфейса.
Если код запускает задачи из других потоков, используйте следующий шаблон, чтобы создать ссылку на поток пользовательского интерфейса, и задача по-прежнему может вернуться к нему:
static Context uiContext = TaskScheduler.FromCurrentSynchronizationContext();
Вызов в потоке пользовательского интерфейса
Для кода, который не использует библиотеку параллельных задач, каждая платформа имеет собственный синтаксис для маршалинга операций обратно в поток пользовательского интерфейса:
- iOS —
owner.BeginInvokeOnMainThread(new NSAction(action))
- Android —
owner.RunOnUiThread(action)
- Xamarin.Forms —
Device.BeginInvokeOnMainThread(action)
- Windows —
Deployment.Current.Dispatcher.BeginInvoke(action)
Для синтаксического синтаксиса iOS и Android требуется доступ к классу context, что означает, что код должен передать этот объект в любые методы, требующие обратного вызова в потоке пользовательского интерфейса.
Чтобы выполнить вызовы потока пользовательского интерфейса в общем коде, следуйте примеру IDispatchOnUIThread (любезно @follesoe). Объявите и программируете IDispatchOnUIThread
интерфейс в общем коде, а затем реализуйте классы для конкретной платформы, как показано ниже:
// program to the interface in shared code
public interface IDispatchOnUIThread {
void Invoke (Action action);
}
// iOS
public class DispatchAdapter : IDispatchOnUIThread {
public readonly NSObject owner;
public DispatchAdapter (NSObject owner) {
this.owner = owner;
}
public void Invoke (Action action) {
owner.BeginInvokeOnMainThread(new NSAction(action));
}
}
// Android
public class DispatchAdapter : IDispatchOnUIThread {
public readonly Activity owner;
public DispatchAdapter (Activity owner) {
this.owner = owner;
}
public void Invoke (Action action) {
owner.RunOnUiThread(action);
}
}
// WP7
public class DispatchAdapter : IDispatchOnUIThread {
public void Invoke (Action action) {
Deployment.Current.Dispatcher.BeginInvoke(action);
}
}
Разработчики Xamarin.Forms должны использовать Device.BeginInvokeOnMainThread
общий код (общие проекты или PCL).
Возможности платформы и устройства и снижение производительности
Дополнительные примеры работы с разными возможностями приведены в документации по возможностям платформы. Он занимается обнаружением различных возможностей и способом корректного снижения производительности приложения для обеспечения хорошего взаимодействия с пользователем, даже если приложение не может работать с его полным потенциалом.