共用方式為


第 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 電話 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線程!

有時候,避免在 ContinueWithResult 方法上使用 或 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 範例會示範此範例。