第 5 部分 - 实际代码共享策略Part 5 - Practical Code Sharing Strategies

本部分提供了有关如何为常见应用程序方案共享代码的示例。This section gives examples of how to share code for common application scenarios.

数据层Data Layer

数据层由存储引擎和用于读取和写入信息的方法组成。The data layer consists of a storage engine and methods to read and write information. 为实现性能、灵活性和跨平台兼容性,建议对 Xamarin 跨平台应用程序使用 SQLite 数据库引擎。For performance, flexibility and cross-platform compatibility the SQLite database engine is recommended for Xamarin cross-platform applications. 它在各种平台(包括 Windows、Android、iOS 和 Mac)上运行。It runs on a wide variety of platforms including Windows, Android, iOS and Mac.

SQLiteSQLite

SQLite 是一个开源数据库实现。SQLite is an open-source database implementation. 可以在SQLite.org中找到源和文档。SQLite 支持适用于每个移动平台:The source and documentation can be found at SQLite.org. SQLite support is available on each mobile platform:

即使在所有平台上都提供了数据库引擎,访问数据库的本机方法也不同。Even with the database engine available on all platforms, the native methods to access the database are different. IOS 和 Android 都提供内置 Api 来访问可从 Xamarin 或 Xamarin 使用的 SQLite,但使用本机 SDK 方法不能共享代码(可能是 SQL 查询本身的情况除外,假设它们存储为字符串).Both iOS and Android offer built-in APIs to access SQLite that could be used from Xamarin.iOS or Xamarin.Android, however using the native SDK methods offers no ability to share code (other than perhaps the SQL queries themselves, assuming they’re stored as strings). 有关本机数据库功能的详细信息,请搜索 iOS 或 Android SQLiteOpenHelper 类中的 CoreData;由于这些选项不是跨平台的,因此它们超出了本文档的范围。For details about native database functionality search for CoreData in iOS or Android’s SQLiteOpenHelper class; because these options are not cross-platform they are beyond the scope of this document.

ADO.NETADO.NET

Xamarin 和 Xamarin 都支持 System.DataMono.Data.Sqlite (有关详细信息,请参阅 Xamarin文档)。Both Xamarin.iOS and Xamarin.Android support System.Data and Mono.Data.Sqlite (see the Xamarin.iOS documentation for more info). 通过使用这些命名空间,可以编写适用于这两个平台的 ADO.NET 代码。Using these namespaces allows you to write ADO.NET code that works on both platforms. 编辑项目的引用以包括 System.Data.dllMono.Data.Sqlite.dll 并将这些 using 语句添加到代码中:Edit the project’s references to include System.Data.dll and Mono.Data.Sqlite.dll and add these using statements to your code:

using System.Data;
using Mono.Data.Sqlite;

下面的示例代码将起作用:Then the following sample code will work:

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 实现会在不同的方法和类之间进行拆分(此示例仅用于演示目的)。Real-world implementations of ADO.NET would obviously be split across different methods and classes (this example is for demonstration purposes only).

SQLite-NET –跨平台 ORMSQLite-NET – Cross-Platform ORM

ORM (或对象关系映射器)尝试简化在类中建模的数据的存储。An ORM (or Object-Relational Mapper) attempts to simplify storage of data modeled in classes. ORM 添加了一层代码来执行此工作,而不是手动编写创建表或选择、插入和删除从类字段和属性中手动提取的数据的 SQL 查询。Rather than manually writing SQL queries that CREATE TABLEs or SELECT, INSERT and DELETE data that is manually extracted from class fields and properties, an ORM adds a layer of code that does that for you. 使用反射检查类的结构,ORM 可以自动创建与类匹配的表和列,并生成查询以读取和写入数据。Using reflection to examine the structure of your classes, an ORM can automatically create tables and columns that match a class and generate queries to read and write the data. 这样,应用程序代码就可以轻松地将对象实例发送和检索到 ORM,后者负责处理所有的 SQL 操作。This allows application code to simply send and retrieve object instances to the ORM, which takes care of all the SQL operations under the hood.

SQLite-NET 充当简单的 ORM,使你能够在 SQLite 中保存和检索类。SQLite-NET acts as a simple ORM that will allow you to save and retrieve your classes in SQLite. 它通过编译器指令和其他技巧的组合,隐藏跨平台 SQLite 访问的复杂性。It hides the complexity of cross platform SQLite access with a combination of compiler directives and other tricks.

SQLite-NET 的功能:Features of SQLite-NET:

  • 表是通过向模型类添加特性来定义的。Tables are defined by adding attributes to Model classes.
  • 数据库实例由 SQLiteConnection 的子类(在 SQLite 网络库中为 main 类)表示。A database instance is represented by a subclass of SQLiteConnection , the main class in the SQLite-Net library.
  • 可以使用对象插入、查询和删除数据。Data can be inserted, queried and deleted using objects. 不需要 SQL 语句(不过,如果需要,可以编写 SQL 语句)。No SQL statements are required (although you can write SQL statements if required).
  • 可对 SQLite-NET 返回的集合执行基本 Linq 查询。Basic Linq queries can be performed on the collections returned by SQLite-NET.

github 上,在 github 上提供了有关 sqlite 网络的源代码和文档,并在这两种情况下均已实现。The source code and documentation for SQLite-NET is available at SQLite-Net on github and has been implemented in both case-studies. 下面显示了一个简单的 SQLITE-NET 代码示例。A simple example of SQLite-NET code (from the Tasky Pro case study) is shown below.

首先,TodoItem 类使用特性将字段定义为数据库主键:First, the TodoItem class uses attributes to define a field to be a database primary key:

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; }
}

这允许在 SQLiteConnection 实例上使用以下代码行(而不是 SQL 语句)创建 TodoItem 表:This allows a TodoItem table to be created with the following line of code (and no SQL statements) on an SQLiteConnection instance:

CreateTable<TodoItem> ();

还可以通过 SQLiteConnection 上的其他方法对表中的数据进行操作(同样,无需 SQL 语句):Data in the table can also be manipulated with other methods on the SQLiteConnection (again, without requiring SQL statements):

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

有关完整示例,请参阅案例研究源代码。See the case study source code for complete examples.

文件访问File Access

文件访问被确定为任何应用程序的关键部分。File access is certain to be a key part of any application. 可能是应用程序的一部分的常见文件示例包括:Common examples of files that might be part of an application include:

  • SQLite 数据库文件。SQLite database files.
  • 用户生成的数据(文本、图像、声音、视频)。User-generated data (text, images, sound, video).
  • 已下载用于缓存的数据(图像、html 或 PDF 文件)。Downloaded data for caching (images, html or PDF files).

System.IO 直接访问System.IO Direct Access

Xamarin 和 Xamarin 都允许使用 System.IO 命名空间中的类进行文件系统访问。Both Xamarin.iOS and Xamarin.Android allow file system access using classes in the System.IO namespace.

每个平台都有不同的访问限制,必须加以考虑:Each platform does have different access restrictions that must be taken into consideration:

  • iOS 应用程序在文件系统访问受限的沙盒中运行。iOS applications run in a sandbox with very restricted file-system access. Apple 进一步决定了应如何使用文件系统,方法是指定已备份的某些位置(以及其他未备份的位置)。Apple further dictates how you should use the file system by specifying certain locations that are backed-up (and others that are not). 有关更多详细信息,请参阅使用Xamarin 中的文件系统指南。Refer to the Working with the File System in Xamarin.iOS guide for more details.
  • Android 还限制了对与应用程序相关的某些目录的访问,但它也支持外部媒体(例如Android also restricts access to certain directories related to the application, but it also supports external media (eg. SD 卡)和访问共享数据。SD cards) and accessing shared data.
  • Windows Phone 8 (Silverlight)不允许直接访问文件–只能使用 IsolatedStorage操作文件。Windows Phone 8 (Silverlight) do not allow direct file access – files can only be manipulated using IsolatedStorage.
  • Windows 8.1 WinRT 和 Windows 10 UWP 项目仅通过 Windows.Storage Api 提供异步文件操作,这不同于其他平台。Windows 8.1 WinRT and Windows 10 UWP projects only offer asynchronous file operations via Windows.Storage APIs, which are different from the other platforms.

IOS 和 Android 示例Example for iOS and Android

下面显示了写入和读取文本文件的简单示例。A trivial example that writes and reads a text file is shown below. 使用 Environment.GetFolderPath 允许在 iOS 和 Android 上运行相同的代码,每个代码都基于文件系统约定返回有效的目录。Using Environment.GetFolderPath allows the same code to run on iOS and Android, which each return a valid directory based on their filesystem conventions.

string filePath = Path.Combine (
        Environment.GetFolderPath (Environment.SpecialFolder.Personal),
        "MyFile.txt");
System.IO.File.WriteAllText (filePath, "Contents of text file");
Console.WriteLine (System.IO.ReadAllText (filePath));

有关特定于 iOS 的文件系统功能的详细信息,请参阅使用文件系统的 Xamarin。Refer to the Xamarin.iOS Working with the File System document for more information on iOS-specific filesystem functionality. 编写跨平台文件访问代码时,请记住,某些文件系统区分大小写,并且具有不同的目录分隔符。When writing cross-platform file access code, remember that some file-systems are case-sensitive and have different directory separators. 最好始终对文件名使用相同的大小写,并在构造文件或目录路径时使用 Path.Combine() 方法。It is good practice to always use the same casing for filenames and the Path.Combine() method when constructing file or directory paths.

适用于 Windows 8 和 Windows 10 的 windows 存储Windows.Storage for Windows 8 and Windows 10

用 Xamarin Book 创建移动应用一书 第20章。Async 和 File i/o 包括Windows 8.1 和 Windows 10 的示例The Creating Mobile Apps with Xamarin.Forms book Chapter 20. Async and File I/O includes samples for Windows 8.1 and Windows 10.

使用DependencyService可以使用受支持的 api 在这些平台上读取和文件文件:Using a DependencyService it's possible to read and file files on these platforms using the supported APIs:

StorageFolder localFolder = ApplicationData.Current.LocalFolder;
IStorageFile storageFile = await localFolder.CreateFileAsync("MyFile.txt",
                                        CreationCollisionOption.ReplaceExisting);
await FileIO.WriteTextAsync(storageFile, "Contents of text file");

请参阅书籍一章了解更多详细信息。Refer to the book chapter for more details.

Windows Phone 7 & 8 (Silverlight)上的独立存储Isolated Storage on Windows Phone 7 & 8 (Silverlight)

独立存储是一种常见的 API,用于在所有 iOS、Android 和更早版本的 Windows Phone 平台上保存和加载文件。Isolated Storage is a common API for saving and loading files across all iOS, Android, and older Windows Phone platforms.

它是在 Windows Phone (Silverlight)中实现的文件访问的默认机制,该机制已在 Xamarin 和 Xamarin 中实现,以允许写入常见文件访问代码。It is the default mechanism for file access in Windows Phone (Silverlight) that has been implemented in Xamarin.iOS and Xamarin.Android to allow common file-access code to be written. 可在共享项目中的所有三个平台上引用 System.IO.IsolatedStorage 类。The System.IO.IsolatedStorage class can be referenced across all three platforms in a Shared Project.

有关详细信息,请参阅Windows Phone 的独立存储概述Refer to the Isolated Storage Overview for Windows Phone for more information.

独立存储 Api 在可移植类库中不可用。The Isolated Storage APIs are not available in Portable Class Libraries. PCL 的一种替代方法是PCLStorage NuGetOne alternative for PCL is the PCLStorage NuGet

Pcl 中的跨平台文件访问Cross-platform file access in PCLs

此外,还提供了与 PCL 兼容的 Nuget – PCLStorage ,可跨平台文件访问支持 Xamarin 的平台和最新的 Windows api。There is also a PCL-compatible Nuget – PCLStorage – that facilities cross-platform file access for Xamarin-supported platforms and the latest Windows APIs.

网络操作Network Operations

大多数移动应用程序都有网络组件,例如:Most mobile applications will have networking component, for example:

  • 下载图像、视频和音频(例如Downloading images, video and audio (eg. 缩略图、照片、音乐。thumbnails, photos, music).
  • 下载文档(例如Downloading documents (eg. HTML、PDF)。HTML, PDF).
  • 上载用户数据(如照片或文本)。Uploading user data (such as photos or text).
  • 访问 web 服务或第三方 Api (包括 SOAP、XML 或 JSON)。Accessing web services or 3rd party APIs (including SOAP, XML or JSON).

.NET Framework 提供了几个不同的类来访问网络资源: HttpClientWebClientHttpWebRequestThe .NET Framework provides a few different classes for accessing network resources: HttpClient, WebClient, and HttpWebRequest.

HttpClientHttpClient

System.Net.Http 命名空间中的 HttpClient 类在 Xamarin、Xamarin 和大多数 Windows 平台中可用。The HttpClient class in the System.Net.Http namespace is available in Xamarin.iOS, Xamarin.Android, and most Windows platforms. 有一个MICROSOFT HTTP 客户端库 Nuget ,可用于将此 API 引入可移植类库(和 Windows Phone 8 Silverlight)。There is a Microsoft HTTP Client Library Nuget that can be used to bring this API into Portable Class Libraries (and Windows Phone 8 Silverlight).

var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://xamarin.com");
var response = await myClient.SendAsync(request);

WebClientWebClient

WebClient 类提供了一个简单的 API,用于从远程服务器检索远程数据。The WebClient class provides a simple API to retrieve remote data from remote servers.

通用 Windows 平台操作必须是异步的,尽管 Xamarin 和 xamarin 支持同步操作(可在后台线程上完成)。Universal Windows Platform operations must be async, even though Xamarin.iOS and Xamarin.Android support synchronous operations (which can be done on background threads).

简单异步 WebClient 操作的代码是:The code for a simple asychronous WebClient operation is:

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 还具有用于检索二进制数据的 DownloadFileCompletedDownloadFileAsyncWebClient also has DownloadFileCompleted and DownloadFileAsync for retrieving binary data.

HttpWebRequestHttpWebRequest

HttpWebRequestWebClient 提供更多的自定义,因此需要更多代码才能使用。HttpWebRequest offers more customization than WebClient and as a result requires more code to use.

简单同步 HttpWebRequest 操作的代码如下:The code for a simple synchronous HttpWebRequest operation is:

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
    }
}

Web 服务文档中提供了一个示例。There is an example in our Web Services documentation.

可访问性Reachability

移动设备在各种网络条件下运行,从快速 Wi-fi 或4G 连接到不良接收区域和慢边缘数据链接。Mobile devices operate under a variety of network conditions from fast Wi-Fi or 4G connections to poor reception areas and slow EDGE data links. 因此,最好在尝试连接到远程服务器之前,检测网络是否可用,如果有,则可以使用哪种类型的网络。Because of this, it is good practice to detect whether the network is available and if so, what type of network is available, before attempting to connect to remote servers.

移动应用在这些情况下可能需要执行的操作包括:Actions a mobile app might take in these situations include:

  • 如果网络不可用,建议用户。If the network is unavailable, advise the user. 如果他们已手动禁用它(例如If they have manually disabled it (eg. 飞行模式或关闭 Wi-fi)后,它们可以解决此问题。Airplane mode or turning off Wi-Fi) then they can resolve the issue.
  • 如果连接是3G,应用程序的行为可能会有所不同(例如,Apple 不允许通过3G 下载大于20Mb 的应用)。If the connection is 3G, applications may behave differently (for example, Apple does not allow apps larger than 20Mb to be downloaded over 3G). 应用程序可以使用此信息在检索大型文件时警告用户过多的下载时间。Applications could use this information to warn the user about excessive download times when retrieving large files.
  • 即使网络可用,也最好在启动其他请求之前验证与目标服务器的连接。Even if the network is available, it is good practice to verify connectivity with the target server before initiating other requests. 这会阻止应用程序的网络操作重复超时,还会允许向用户显示更丰富的错误消息。This will prevent the app’s network operations from timing out repeatedly and also allow a more informative error message to be displayed to the user.

有可用的Xamarin iOS 示例(基于 Apple 的可访问性示例代码),以帮助检测网络可用性。There is a Xamarin.iOS sample available (which is based on Apple’s Reachability sample code ) to help detect network availability.

WebServicesWebServices

请参阅有关使用Web 服务的文档,其中介绍了如何使用 XAMARIN 访问 REST、SOAP 和 WCF 终结点。See our documentation on Working with Web Services, which covers accessing REST, SOAP and WCF endpoints using Xamarin.iOS. 可以手动创建 web 服务请求并分析响应,但是,有一些库可使此方法更简单,包括 Azure、RestSharp 和 ServiceStack。It is possible to hand-craft web service requests and parse the responses, however there are libraries available to make this much simpler, including Azure, RestSharp, and ServiceStack. 甚至可以在 Xamarin 应用程序中访问基本 WCF 操作。Even basic WCF operations can be accessed in Xamarin apps.

AzureAzure

Microsoft Azure 是一种云平台,可为移动应用提供各种服务,包括数据存储和同步以及推送通知。Microsoft Azure is a cloud platform that provides a wide variety of services for mobile apps, including data storage and sync, and push notifications.

若要免费试用,请访问azure.microsoft.comVisit azure.microsoft.com to try it for free.

RestSharpRestSharp

RestSharp 是一个 .NET 库,可包含在移动应用程序中,以提供简化对 web 服务的访问的 REST 客户端。RestSharp is a .NET library that can be included in mobile applications to provide a REST client that simplifies access to web services. 它通过提供用于请求数据和分析 REST 响应的简单 API 来帮助。It helps by providing a simple API to request data and parse the REST response. RestSharp 非常有用RestSharp can be useful

RestSharp 网站包含了有关如何使用 RESTSHARP 实现 REST 客户端的文档The RestSharp website contains documentation on how to implement a REST client using RestSharp. RestSharp 在github上提供 Xamarin 和 xamarin。RestSharp provides Xamarin.iOS and Xamarin.Android examples on github.

Web 服务文档中也有一个 Xamarin iOS 代码片段。There is also a Xamarin.iOS code snippet in our Web Services documentation.

ServiceStackServiceStack

与 RestSharp 不同,ServiceStack 既是用于承载 web 服务的服务器端解决方案,也是可在移动应用程序中实现以访问这些服务的客户端库。Unlike RestSharp, ServiceStack is both a server-side solution to host a web service as well as a client library that can be implemented in mobile applications to access those services.

ServiceStack 网站说明了项目的目的和文档和代码示例的链接。The ServiceStack website explains the purpose of the project and links to document and code samples. 这些示例包括 web 服务的完整服务器端实现,以及可以访问它的各种客户端应用程序。The examples include a complete server-side implementation of a web service as well as various client-side applications that can access it.

ServiceStack 网站上有一个Xamarin iOS 示例,并在我们的Web 服务文档中提供了一个代码片段。There is a Xamarin.iOS example on the ServiceStack website, and a code snippet in our Web Services documentation.

WCFWCF

Xamarin 工具可帮助你使用某些 Windows Communication Foundation (WCF)服务。Xamarin tools can help you consume some Windows Communication Foundation (WCF) services. 通常,Xamarin 支持与 Silverlight 运行时随附的同一客户端的 WCF 子集。In general, Xamarin supports the same client-side subset of WCF that ships with the Silverlight runtime. 这包括 WCF 的最常见的编码和协议实现:使用 BasicHttpBinding通过 HTTP 传输协议文本编码的 SOAP 消息。This includes the most common encoding and protocol implementations of WCF: text-encoded SOAP messages over the HTTP transport protocol using the BasicHttpBinding.

由于 WCF 框架的大小和复杂性,可能存在当前和未来的服务实现,这些实现将超出 Xamarin 的客户端子集域支持的范围。Due to the size and complexity of the WCF framework, there may be current and future service implementations that will fall outside of the scope supported by Xamarin’s client-subset domain. 此外,WCF 支持需要使用仅在 Windows 环境中可用的工具来生成代理。In addition, WCF support requires the use of tools only available in a Windows environment to generate the proxy.

线程Threading

对于移动应用程序而言,应用程序响应能力非常重要–用户希望应用程序能够快速加载和执行。Application responsiveness is important for mobile applications – users expect applications to load and perform quickly. 停止接受用户输入的 "冻结" 屏幕将显示,指出应用程序已崩溃,因此不需要将 UI 线程与长时间运行的阻塞调用(如网络请求或慢本地操作,如解压缩文件)结合使用。A ‘frozen’ screen that stops accepting user-input will appear to indicate the application has crashed, so it is important not to tie up the UI thread with long-running blocking calls such as network requests or slow local operations (such as unzipping a file). 特别是启动过程不应包含长时间运行的任务,所有移动平台都将终止加载时间太长的应用程序。In particular the startup process should not contain long-running tasks – all mobile platforms will kill an app that takes too long to load.

这意味着你的用户界面应实现 "进度指示器" 或其他快速显示的 "使用" UI,以及执行后台操作的异步任务。This means your user interface should implement a ‘progress indicator’ or otherwise ‘useable’ UI that is quick to display, and asynchronous tasks to perform background operations. 执行后台任务需要使用线程,这意味着后台任务需要一种方法来与主线程通信以指示进度或完成时间。Executing background tasks requires the use of threads, which means the background tasks needs a way to communicate back to the main thread to indicate progress or when they have completed.

并行任务库Parallel Task Library

用并行任务库创建的任务可以异步运行并在其调用线程上返回,使其在不阻止用户界面的情况下触发长时间运行的操作非常有用。Tasks created with the Parallel Task Library can run asynchronously and return on their calling thread, making them very useful for triggering long-running operations without blocking the user interface.

简单的并行任务操作可能如下所示:A simple parallel task operation might look like this:

using System.Threading.Tasks;
void MainThreadMethod ()
{
    Task.Factory.StartNew (() => wc.DownloadString ("http://...")).ContinueWith (
        t => label.Text = t.Result, TaskScheduler.FromCurrentSynchronizationContext()
    );
}

密钥是 TaskScheduler.FromCurrentSynchronizationContext() 的,这将重复使用调用方法的线程的 SynchronizationContext (此处运行 MainThreadMethod的主线程)作为封送回线程调用的方法。The key is TaskScheduler.FromCurrentSynchronizationContext() which will reuse the SynchronizationContext.Current of the thread calling the method (here the main thread that is running MainThreadMethod) as a way to marshal back calls to that thread. 这意味着,如果在 UI 线程上调用方法,则会在 UI 线程上运行 ContinueWith 操作。This means if the method is called on the UI thread, it will run the ContinueWith operation back on the UI thread.

如果代码要从其他线程启动任务,请使用下面的模式创建对 UI 线程的引用,并且任务仍可以回调到该线程:If the code is starting tasks from other threads, use the following pattern to create a reference to the UI thread and the task can still call back to it:

static Context uiContext = TaskScheduler.FromCurrentSynchronizationContext();

在 UI 线程上调用Invoking on the UI Thread

对于不利用并行任务库的代码,每个平台都有自己的语法,用于将操作封送回 UI 线程:For code that doesn’t utilize the Parallel Task Library, each platform has its own syntax for marshaling operations back to the UI thread:

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

IOS 和 Android 语法都要求有一个可用的 "context" 类,这意味着代码需要将此对象传递到需要在 UI 线程上回调的任何方法。Both the iOS and Android syntax requires a ‘context’ class to be available which means the code needs to pass this object into any methods that require a callback on the UI thread.

若要在共享代码中调用 UI 线程,请按照IDispatchOnUIThread 示例操作( @follesoe)。To make UI thread calls in shared code, follow the IDispatchOnUIThread example (courtesy of @follesoe). 在共享代码中声明并编程到 IDispatchOnUIThread 接口,然后实现特定于平台的类,如下所示:Declare and program to an IDispatchOnUIThread interface in the shared code and then implement the platform-specific classes as shown here:

// 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 开发人员应使用通用代码(共享项目或 PCL)中Device.BeginInvokeOnMainThreadXamarin.Forms developers should use Device.BeginInvokeOnMainThread in common code (Shared Projects or PCL).

平台和设备功能和降级Platform and Device Capabilities and Degradation

平台功能文档中提供了处理不同功能的更具体的示例。Further specific examples of dealing with different capabilities are given in the Platform Capabilities documentation. 它处理的是检测不同的功能,以及如何适当地降低应用程序的性能,以提供良好的用户体验,即使应用程序无法充分发挥其潜能。It deals with detecting different capabilities and how to gracefully degrade an application to provide a good user experience, even when the app can’t operate to its full potential.