共用方式為


第 20 章的摘要。 非同步與檔案 I/O

注意

這本書於2016年春季出版,此後一直沒有更新。 這本書中有很多仍然有價值,但一些材料已經過時,有些主題不再完全正確或完整。

圖形用戶介面必須循序回應使用者輸入事件。 這表示使用者輸入事件的所有處理都必須發生在單個線程中,通常稱為 主線程UI 線程

用戶預期圖形使用者介面會回應。 這表示程式必須快速處理使用者輸入事件。 如果不可能,則必須將處理降級至執行中的次要線程。

這本書中的數個範例程式已使用 類別 WebRequest 。 在此類別中, BeginGetResponse 方法會啟動背景工作線程,此線程會在完成時呼叫回呼函式。 不過,該回呼函式會在背景工作線程中執行,因此程式必須呼叫 Device.BeginInvokeOnMainThread 方法來存取使用者介面。

注意

Xamarin.Forms 程序應該使用 HttpClient 而不是 WebRequest 透過因特網存取檔案。 HttpClient 支援異步操作。

.NET 和 C# 提供更現代化的異步處理方法。 這牽涉到 TaskTask<TResult> 類別,以及 和 System.Threading.Tasks 命名空間中的其他System.Threading類型,以及 C# 5.0 asyncawait關鍵詞。 這就是本章的重點。

從回呼到 await

類別 Page 本身包含三種顯示警示方塊的異步方法:

Task物件表示這些方法會實作工作型異步模式,稱為 TAP。 這些 Task 物件會從方法快速傳回。 傳 Task<T> 回值構成一個「承諾」,表示當工作完成時,將會有類型的 TResult 值可供使用。 傳 Task 回值表示將完成但未傳回值的異步動作。

在這些情況下,當使用者關閉警示方塊時, Task 就會完成 。

具有回呼的警示

AlertCallbacks 範例示範如何使用回呼方法來處理Task<bool>傳回物件和Device.BeginInvokeOnMainThread呼叫。

具有 Lambda 的警示

AlertLambdas 範例示範如何使用匿名 Lambda 函式來處理TaskDevice.BeginInvokeOnMainThread呼叫。

具有 await 的警示

更直接的方法牽涉到 C# 5 中引進的 asyncawait 關鍵詞。 AlertAwait 範例會示範其用法。

無任何警示

如果異步方法傳 Task 回 而不是 Task<TResult>,則如果程式不需要知道異步工作何時完成,就不需要使用這些技術。 NothingAlert 範例會示範這一點。

以異步方式儲存程式設定

SaveProgramChanges 範例示範 SavePropertiesAsync 如何使用 的 方法來Application儲存程式設定,因為它們變更而不覆寫 OnSleep 方法。

與平台無關的定時器

Task.Delay您可以使用 來建立與平台無關的定時器。 TaskDelayClock 範例會示範這一點。

檔案輸入/輸出

傳統上,.NET System.IO 命名空間是檔案 I/O 支援的來源。 雖然此命名空間中的某些方法支援異步操作,但大部分都不支援。 命名空間也支持數個執行複雜檔案 I/O 函式的簡單方法呼叫。

好消息和壞消息

支援應用程式本機記憶體支援 Xamarin.Forms 的所有平臺, 這是應用程式私人的記憶體。

Xamarin.iOS 和 Xamarin.Android 連結庫包含 Xamarin 針對這兩個平台明確量身打造的 .NET 版本。 這些包含的類別 System.IO 可讓您用來在這兩個平臺中搭配應用程式本機記憶體執行檔案 I/O。

不過,如果您在 PCL 中Xamarin.Forms搜尋這些System.IO類別,則找不到這些類別。 問題是,Microsoft已針對 Windows 執行階段 API 完全修改的檔案 I/O。 以 Windows 8.1、Windows Phone 8.1 和 通用 Windows 平台 為目標的程式不會用於System.IO檔案 I/O。

這表示您必須使用 DependencyService (第 9 章中 討論的第一個討論。平臺特定的 API 呼叫 ,以實作檔案 I/O。

注意

可攜式類別連結庫已取代為 .NET Standard 2.0 連結庫,而 .NET Standard 2.0 支援 System.IO 所有 Xamarin.Forms 平台的類型。 不再需要針對大部分的檔案 I/O 工作使用 DependencyService 。 如需更現代化的檔案 I/O 方法,請參閱 中的 Xamarin.Forms 檔案處理。

跨平台檔案 I/O 的第一次拍攝

TextFileTryout 範例會IFileHelper定義檔案 I/O 的介面,以及所有平臺中這個介面的實作。 不過,Windows 執行階段 實作無法與這個介面中的方法搭配使用,因為 Windows 執行階段 檔案 I/O 方法是異步的。

容納 Windows 執行階段 檔案 I/O

在 Windows 執行階段下執行的程式會針對檔案 I/O 使用 和 Windows.Storage.Streams 命名空間中的Windows.Storage類別,包括應用程式本機記憶體。 由於Microsoft判斷任何需要超過 50 毫秒的作業都應該是異步的,以避免封鎖 UI 線程,因此這些檔案 I/O 方法大多是異步的。

示範這個新方法的程式代碼將會位於連結庫中,讓其他應用程式可以使用它。

平台特定程式庫

最好將可重複使用的程式代碼儲存在連結庫中。 當不同可重複使用的程式代碼片段針對完全不同的操作系統時,這顯然比較困難。

Xamarin.FormsBook.Platform 解決方案示範一種方法。 此解決方案包含七個不同的專案:

所有個別的平台專案(除了 Xamarin.FormsBook.Platform.WinRT 除外)都有 Book.PlatformXamarin.Forms參考。 這三個 Windows 專案具有 Book.Platform.WinRTXamarin.Forms參考。

所有專案都包含靜態 Toolkit.Init 方法,以確保連結庫未由應用程式解決方案中的 Xamarin.Forms 專案直接參考時載入。

Xamarin.FormsBook.Platform 專案包含新的IFileHelper介面。 所有方法現在都有後 Async 綴和傳回 Task 對象的名稱。

Xamarin.FormsBook.Platform.WinRT 專案包含 FileHelper Windows 執行階段 的類別。

Xamarin.FormsBook.Platform.iOS 專案包含 iOS 的FileHelper類別。 這些方法現在必須是異步的。 某些方法會使用和StreamReaderStreamWriter定義的異步方法版本: WriteAsyncReadToEndAsync。 其他人則使用 FromResult 方法將結果Task轉換成 物件。

Xamarin.FormsBook.Platform.Android 專案包含 Android 的類似FileHelper類別。

Xamarin.FormsBook.Platform 專案也包含FileHelper可簡化物件使用的DependencyService類別。

若要使用這些連結庫,應用程式解決方案必須包含 Book.Platform 解決方案中的所有Xamarin.Forms專案,而且每個應用程式專案都必須有 Book.PlatformXamarin.Forms對應文件庫的參考。

TextFileAsync 解決方案示範如何使用 Xamarin.FormsBook.Platform 連結庫。 每個專案都有 對 Toolkit.Init的呼叫。 應用程式會使用異步檔案 I/O 函式。

將它保留在背景中

對多個異步方法進行呼叫的連結庫中的方法,例如 WriteFileAsync Windows 執行階段 FileHelper 類別中的 和 ReadFileASync 方法,可以使用 方法來避免切換回使用者介面線程,讓方法更有效率ConfigureAwait

請勿封鎖UI線程!

有時候,避免在 ContinueWith Result 方法上使用 或 await 屬性,會很誘人。 這應該避免,因為它可以封鎖UI線程,甚至停止響應應用程式。

您自己的可等候方法

您可以將程式代碼傳遞至其中 Task.Run 一個方法,以異步方式執行某些程序代碼。 您可以在處理部分額外負荷的異步方法內呼叫 Task.Run

以下將討論各種 Task.Run 模式。

基本曼德爾布羅特集

若要即時繪製 Mandelbrot 集合,則為 Xamarin.Forms。工具組 連結庫的結構 Complex 與 命名空間中的 System.Numerics 結構類似。

MandelbrotSet 範例在其程式代碼後置檔案中具有方法CalculateMandeblotAsync,可計算基本的黑白 Mandelbrot 集合,並使用 BmpMaker 將它放在位圖上。

標記進度

若要報告異步方法的進度,您可以具現化 Progress<T> 類別,並定義異步方法,以具有 類型的 IProgress<T>自變數。 這是在 MandelbrotProgress 範例中示範的。

取消作業

您也可以撰寫異步方法以取消。 您會從名為 的 CancellationTokenSource類別開始。 屬性 Token 是類型的 CancellationToken值。 這會傳遞至異步函式。 程式會呼叫 Cancel 的方法 CancellationTokenSource (通常是為了回應用戶的動作),以取消異步函式。

如果 屬性為 true,或直接呼叫 ThrowIfCancellationRequested 方法,異步方法可以定期檢查 IsCancellationRequested 的 屬性CancellationToken並結束,在此情況下,方法會以 結尾OperationCancelledException

MandelbrotCancellation 範例示範如何使用可取消的函式。

An MVVM Mandelbrot

MandelbrotXF 範例具有更廣泛的使用者介面,而且主要以 和 MandelbrotViewModel 類別為基礎MandelbrotModel

Mandelbrot X F 的三重螢幕快照

回到網路

WebRequest某些範例中使用的類別會使用稱為異步程序設計模型或APM的舊式異步通訊協定。 您可以使用 類別中的TaskFactory其中FromAsync一種方法,將這類類別轉換成新式 TAP 通訊協定。 ApmToTap 範例會示範此範例。