Část 5 – Praktické strategie sdílení kódu
V této části najdete příklady sdílení kódu pro běžné scénáře aplikací.
Datová vrstva
Datová vrstva se skládá z modulu úložiště a metod pro čtení a zápis informací. Pro zajištění výkonu, flexibility a kompatibility napříč platformami se doporučuje databázový stroj SQLite pro multiplatformní aplikace Xamarinu. Běží na nejrůznějších platformách, včetně Windows, Androidu, iOS a Mac.
SQLite
SQLite je opensourcová implementace databáze. Zdroj a dokumentace najdete v SQLite.org. Podpora SQLite je dostupná na každé mobilní platformě:
- iOS – integrovaný do operačního systému.
- Android – integrovaný do operačního systému od Androidu 2.2 (api level 10).
- Windows – Viz rozšíření SQLite pro Univerzální platforma Windows.
I s databázovým strojem dostupným na všech platformách se nativní metody pro přístup k databázi liší. IOS i Android nabízejí integrovaná rozhraní API pro přístup k rozhraníM SQLite, která se dají použít z Xamarin.iOS nebo Xamarin.Androidu, ale použití nativních metod sady SDK nenabízí možnost sdílet kód (kromě samotných dotazů SQL za předpokladu, že jsou uložené jako řetězce). Podrobnosti o nativních funkcích databáze najdete CoreData
ve třídě iOS nebo Androidu SQLiteOpenHelper
, protože tyto možnosti nejsou pro různé platformy nad rámec tohoto dokumentu.
ADO.NET
Podpora System.Data
Xamarin.iOS i Xamarin.Android a Mono.Data.Sqlite
(další informace najdete v dokumentaci k Xamarin.iOS).
Použití těchto oborů názvů umožňuje psát ADO.NET kód, který funguje na obou platformách. Upravte odkazy projektu tak, aby zahrnovaly System.Data.dll
a Mono.Data.Sqlite.dll
přidaly tyto příkazy using do kódu:
using System.Data;
using Mono.Data.Sqlite;
Pak bude fungovat následující ukázkový kód:
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 ();
Skutečné implementace ADO.NET by se samozřejmě rozdělily mezi různé metody a třídy (tento příklad je pouze pro demonstrační účely).
SQLite-NET – Multiplatformní ORM
ORM (neboli objektově-relační mapovač) se pokouší zjednodušit ukládání dat modelovaných ve třídách. Místo ručního zápisu dotazů SQL, které vytvářejí objekty TABLEs nebo SELECT, vložte a ODSTRAŇte data, která se ručně extrahují z polí a vlastností třídy, přidá ORM vrstvu kódu, která to udělá za vás. Pomocí reflexe pro zkoumání struktury tříd může ORM automaticky vytvářet tabulky a sloupce, které odpovídají třídě, a generovat dotazy pro čtení a zápis dat. To umožňuje kódu aplikace jednoduše odesílat a načítat instance objektů do ORM, což se postará o všechny operace SQL pod kapotou.
SQLite-NET funguje jako jednoduchý ORM, který vám umožní ukládat a načítat třídy v SQLite. Skrývá složitost přístupu SQLite pro různé platformy pomocí kombinace direktiv kompilátoru a dalších triků.
Funkce SQLite-NET:
- Tabulky jsou definovány přidáním atributů do tříd modelu.
- Instance databáze je reprezentována podtřídou
SQLiteConnection
třídy , hlavní třídy v knihovně SQLite-Net. - Data lze vložit, dotazovat a odstranit pomocí objektů. Nejsou vyžadovány žádné příkazy SQL (i když v případě potřeby můžete psát příkazy SQL).
- Základní dotazy Linq lze provádět na kolekcích vrácených rozhraním SQLite-NET.
Zdrojový kód a dokumentace pro SQLite-NET jsou k dispozici na webu SQLite-Net na GitHubu a byly implementovány v obou případových studiích. Níže je uveden jednoduchý příklad kódu SQLite-NET (z případové studie Tasky Pro ).
TodoItem
Třída nejprve pomocí atributů definuje pole, které má být primárním klíčem databáze:
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; }
}
To umožňuje TodoItem
vytvoření tabulky s následujícím řádkem kódu (a bez příkazů SQL) v SQLiteConnection
instanci:
CreateTable<TodoItem> ();
Data v tabulce lze také manipulovat s jinými metodami ( SQLiteConnection
opět bez vyžadování příkazů 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
Kompletní příklady najdete ve zdrojovém kódu případové studie.
Přístup k souborům
Přístup k souborům je určitě klíčovou součástí jakékoli aplikace. Mezi běžné příklady souborů, které můžou být součástí aplikace, patří:
- Soubory databáze SQLite.
- Uživatelsky generovaná data (text, obrázky, zvuk, video).
- Stažená data pro ukládání do mezipaměti (obrázky, soubory HTML nebo PDF)
System.IO přímý přístup
Xamarin.iOS i Xamarin.Android umožňují přístup k systému souborů pomocí tříd v System.IO
oboru názvů.
Každá platforma má různá omezení přístupu, která je potřeba vzít v úvahu:
- Aplikace pro iOS běží v sandboxu s velmi omezeným přístupem k systému souborů. Apple dále určuje, jak byste měli systém souborů používat zadáním určitých umístění zálohovaných (a jiných, které nejsou). Další podrobnosti najdete v příručce Práce se systémem souborů v Xamarin.iOS.
- Android také omezuje přístup k určitým adresářům souvisejícím s aplikací, ale podporuje také externí média (např. Karty SD) a přístup ke sdíleným datům
- Windows Phone 8 (Silverlight) nepovolují přímý přístup k souborům – soubory lze manipulovat pouze pomocí
IsolatedStorage
. - Projekty Windows 8.1 WinRT a Windows 10 UPW nabízejí pouze asynchronní operace se soubory prostřednictvím
Windows.Storage
rozhraní API, která se liší od ostatních platforem.
Příklad pro iOS a Android
Triviální příklad, který zapisuje a čte textový soubor, je znázorněn níže.
Použití Environment.GetFolderPath
umožňuje, aby stejný kód běžel v iOSu a Androidu, který každý vrací platný adresář na základě jejich konvencí systému souborů.
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));
Další informace o funkcích systémusouborůch Při psaní přístupového kódu k souborům napříč platformami mějte na paměti, že některé systémy souborů rozlišují malá a velká písmena a mají různé oddělovače adresářů. Při vytváření cest k souborům nebo adresářům je vhodné vždy používat stejná velikost znaků pro názvy souborů a metodu Path.Combine()
.
Windows.Storage pro Windows 8 a Windows 10
The Creating Mobile Apps with Xamarin.Forms bookChapter 20. Asynchronní vstupně-výstupní operace a vstupně-výstupní operace souborů zahrnují ukázky pro Windows 8.1 a Windows 10.
DependencyService
Pomocí podporovaných rozhraní API je možné číst a souborovat soubory na těchto platformách:
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
IStorageFile storageFile = await localFolder.CreateFileAsync("MyFile.txt",
CreationCollisionOption.ReplaceExisting);
await FileIO.WriteTextAsync(storageFile, "Contents of text file");
Další podrobnosti najdete v kapitole knihy 20 .
Izolované úložiště ve Windows Phone 7 a 8 (Silverlight)
Izolované úložiště je společné rozhraní API pro ukládání a načítání souborů na všech platformách iOS, Android a starších platforem Windows Phone.
Jedná se o výchozí mechanismus pro přístup k souborům ve Windows Phone (Silverlight), který byl implementován v Xamarin.iOS a Xamarin.Android, aby bylo možné zapisovat společný kód pro přístup k souborům. Na System.IO.IsolatedStorage
třídu lze odkazovat na všechny tři platformy ve sdíleném projektu.
Další informace najdete v přehledu izolovaného úložiště pro Windows Phone .
Rozhraní API izolovaného úložiště nejsou k dispozici v přenosných knihovnách tříd. Jednou z alternativ pro PCL je NUGet PCLStorage.
Přístup k souborům napříč platformami v souborech PCLS
K dispozici je také nuGet kompatibilní s PCL – PCLStorage – který umožňuje přístup k souborům napříč platformami pro platformy podporované Xamarinem a nejnovější rozhraní API systému Windows.
Síťové operace
Většina mobilních aplikací bude mít například síťovou komponentu:
- Stahování obrázků, videa a zvuku (např. miniatury, fotky, hudba).
- Stahování dokumentů (např. HTML, PDF).
- Nahrávání uživatelských dat (například fotek nebo textu)
- Přístup k webovým službám nebo rozhraním API třetích stran (včetně SOAP, XML nebo JSON)
Rozhraní .NET Framework poskytuje několik různých tříd pro přístup k síťovým prostředkům: HttpClient
, WebClient
a HttpWebRequest
.
HttpClient
Třída HttpClient
v System.Net.Http
oboru názvů je k dispozici v Xamarin.iOS, Xamarin.Android a většině platforem Windows. K přenesení tohoto rozhraní API do přenosných knihoven tříd (a windows Phone 8 Silverlight) je k dispozici Balíček NuGet klientské knihovny MICROSOFT HTTP.
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://xamarin.com");
var response = await myClient.SendAsync(request);
Webový klient
Třída WebClient
poskytuje jednoduché rozhraní API pro načtení vzdálených dat ze vzdálených serverů.
Univerzální platforma Windows operace musí být asynchronní, i když Xamarin.iOS a Xamarin.Android podporují synchronní operace (které je možné provádět na podprocesech na pozadí).
Kód pro jednoduchou asychronous WebClient
operaci je:
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
také má DownloadFileCompleted
a DownloadFileAsync
pro načítání binárních dat.
HttpWebRequest
HttpWebRequest
nabízí více přizpůsobení než WebClient
a v důsledku toho vyžaduje více kódu, který se má použít.
Kód jednoduché synchronní HttpWebRequest
operace je:
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
}
}
Příklad najdete v dokumentaci k webovým službám.
Dosažitelnost
Mobilní zařízení fungují v různých síťových podmínkách od rychlých připojení Wi-Fi nebo 4G až po špatné oblasti příjmu a pomalé datové propojení EDGE. Z tohoto důvodu je vhodné před pokusem o připojení ke vzdáleným serverům zjistit, jestli je síť dostupná, a pokud ano, jaký typ sítě je k dispozici.
Mezi akce, které může mobilní aplikace provádět v těchto situacích, patří:
- Pokud síť není k dispozici, poraďte uživateli. Pokud ho ručně zakázal (např. Režim v letadle nebo vypnutí Wi-Fi) pak můžou tento problém vyřešit.
- Pokud je připojení 3G, můžou se aplikace chovat jinak (například Apple neumožňuje stažení aplikací větších než 20 Mb přes 3G). Aplikace mohou tyto informace použít k upozornění uživatele na nadměrné doby stahování při načítání velkých souborů.
- I v případě, že je síť dostupná, je vhodné před zahájením jiných požadavků ověřit připojení k cílovému serveru. Zabráníte tak opakovanému načasování síťových operací aplikace a umožníte uživateli zobrazit informativní chybovou zprávu.
Webové služby
Podívejte se na naši dokumentaci k práci s webovými službami, která se zabývá přístupem ke koncovým bodům REST, SOAP a WCF pomocí Xamarin.iOS. Je možné ručně vytvořit žádosti o webové služby a analyzovat odpovědi, ale k dispozici jsou knihovny, které to výrazně zjednodušují, včetně Azure, RestSharp a ServiceStack. V aplikacích Xamarin je možné přistupovat i k základním operacím WCF.
Azure
Microsoft Azure je cloudová platforma, která poskytuje širokou škálu služeb pro mobilní aplikace, včetně úložiště dat a synchronizace a nabízených oznámení.
Navštivte azure.microsoft.com vyzkoušet zdarma.
RestSharp
RestSharp je knihovna .NET, která může být součástí mobilních aplikací, aby poskytovala klienta REST, který zjednodušuje přístup k webovým službám. Pomáhá tím, že poskytuje jednoduché rozhraní API pro vyžádání dat a parsování odpovědi REST. RestSharp může být užitečné
Web RestSharp obsahuje dokumentaci k implementaci klienta REST pomocí RestSharp. RestSharp poskytuje příklady Xamarin.iOS a Xamarin.Android na GitHubu.
V dokumentaci k webovým službám je také fragment kódu Xamarin.iOS.
ServiceStack
Na rozdíl od RestSharp je ServiceStack řešení na straně serveru pro hostování webové služby i klientské knihovny, které je možné implementovat v mobilních aplikacích pro přístup k těmto službám.
Web ServiceStack vysvětluje účel projektu a odkazuje na dokumenty a ukázky kódu. Mezi příklady patří kompletní implementace webové služby na straně serveru a také různé aplikace na straně klienta, které k ní mají přístup.
WCF
Nástroje Xamarin vám můžou pomoct využívat některé služby WCF (Windows Communication Foundation). Xamarin obecně podporuje stejnou podmnožinu WCF na straně klienta, která se dodává s modulem runtime Silverlight. Patří sem nejběžnější implementace kódování a protokolu WCF: textově kódované zprávy SOAP přes přenosový protokol HTTP pomocí BasicHttpBinding
protokolu .
Vzhledem k velikosti a složitosti architektury WCF může existovat aktuální a budoucí implementace služeb, které budou spadat mimo rozsah podporovaný doménou klient-podmnožina Xamarin. Kromě toho podpora WCF vyžaduje použití nástrojů, které jsou k dispozici pouze v prostředí Systému Windows k vygenerování proxy serveru.
Dělení na vlákna
Odezva aplikace je důležitá pro mobilní aplikace – uživatelé očekávají, že se aplikace načítají a provádějí rychle. Zdá se, že se zobrazí zablokovaná obrazovka, která přestane přijímat uživatelský vstup, značí chybové ukončení aplikace, takže je důležité nevázat vlákno uživatelského rozhraní s dlouhotrvajícími blokujícími voláními, jako jsou síťové požadavky nebo pomalé místní operace (například rozbalení souboru). Zejména spouštěcí proces by neměl obsahovat dlouhotrvající úlohy – všechny mobilní platformy zabíjejí aplikaci, která trvá příliš dlouho.
To znamená, že vaše uživatelské rozhraní by mělo implementovat indikátor průběhu nebo jinak použitelné uživatelské rozhraní, které je rychlé k zobrazení, a asynchronní úlohy pro provádění operací na pozadí. Provádění úloh na pozadí vyžaduje použití vláken, což znamená, že úlohy na pozadí potřebují způsob, jak komunikovat zpět s hlavním vláknem, aby bylo možné označit průběh nebo po dokončení.
Knihovna paralelních úloh
Úlohy vytvořené pomocí knihovny paralelních úloh můžou běžet asynchronně a vracet se na volající vlákno, což je velmi užitečné pro aktivaci dlouhotrvajících operací bez blokování uživatelského rozhraní.
Jednoduchá paralelní operace úlohy může vypadat takto:
using System.Threading.Tasks;
void MainThreadMethod ()
{
Task.Factory.StartNew (() => wc.DownloadString ("http://...")).ContinueWith (
t => label.Text = t.Result, TaskScheduler.FromCurrentSynchronizationContext()
);
}
Klíč je TaskScheduler.FromCurrentSynchronizationContext()
, který znovu použije SynchronizationContext.Current vlákna volání metody (zde hlavní vlákno, které běží MainThreadMethod
) jako způsob zařazování volání zpět do tohoto vlákna. To znamená, že pokud je metoda volána ve vlákně uživatelského rozhraní, spustí ContinueWith
operaci zpět ve vlákně uživatelského rozhraní.
Pokud kód spouští úlohy z jiných vláken, pomocí následujícího vzoru vytvořte odkaz na vlákno uživatelského rozhraní a úloha se k němu může stále volat:
static Context uiContext = TaskScheduler.FromCurrentSynchronizationContext();
Vyvolání ve vlákně uživatelského rozhraní
Pro kód, který nevyužívá knihovnu paralelních úloh, má každá platforma vlastní syntaxi pro zařazování operací zpět do vlákna uživatelského rozhraní:
- iOS –
owner.BeginInvokeOnMainThread(new NSAction(action))
- Android –
owner.RunOnUiThread(action)
- Xamarin.Forms –
Device.BeginInvokeOnMainThread(action)
- Windows –
Deployment.Current.Dispatcher.BeginInvoke(action)
Syntaxe iOSu i Androidu vyžaduje, aby byla k dispozici třída context, což znamená, že kód musí předat tento objekt do všech metod, které vyžadují zpětné volání ve vlákně uživatelského rozhraní.
Pokud chcete volat vlákno uživatelského rozhraní ve sdíleném kódu, postupujte podle příkladu IDispatchOnUIThread (se svolením @follesoe). Deklarujte a programujte do rozhraní ve sdíleném IDispatchOnUIThread
kódu a pak implementujte třídy specifické pro platformu, jak je znázorněno zde:
// 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);
}
}
Vývojáři Xamarin.Forms by měli používat Device.BeginInvokeOnMainThread
společný kód (sdílené projekty nebo PCL).
Možnosti a snížení výkonu platformy a zařízení
Další konkrétní příklady práce s různými možnostmi jsou uvedeny v dokumentaci k funkcím platformy. Zabývá se zjišťováním různých funkcí a s tím, jak elegantně snížit výkon aplikace tak, aby poskytovala dobré uživatelské prostředí, i když aplikace nemůže fungovat s úplným potenciálem.