非同步支援概觀

C# 5 引進了兩個關鍵詞來簡化異步程序設計:async 和 await。 這些關鍵詞可讓您撰寫簡單的程式代碼,利用工作平行連結庫在另一個線程中執行長時間執行的作業(例如網路存取),並在完成時輕鬆存取結果。 最新版的 Xamarin.iOS 和 Xamarin.Android 支援 async 和 await - 本檔提供搭配 Xamarin 使用新語法的說明和範例。

Xamarin 的異步支援建置在Mono 3.0基礎上,並將 API 配置檔從作為Mobile-friendly 版本的 Silverlight 升級為行動版 .NET 4.5。

概觀

本文件介紹新的異步和 await 關鍵詞,然後逐步解說在 Xamarin.iOS 和 Xamarin.Android 中實作異步方法的一些簡單範例。

如需 C# 5 的新異步功能更完整討論(包括許多範例和不同的使用案例),請參閱異步程序設計一文

範例應用程式會建立簡單的異步 Web 要求(而不封鎖主線程),然後使用下載的 html 和字元計數來更新 UI。

The sample application makes a simple asynchronous web request without blocking the main thread then updates the UI with the downloaded html and character count

Xamarin 的異步支援建置在Mono 3.0基礎上,並將API配置檔從升級為適用於行動裝置的 Silverlight 版本,升級為 .NET 4.5 的行動版。

需求

C# 5 功能需要包含在 Xamarin.iOS 6.4 和 Xamarin.Android 4.8 中的 Mono 3.0。 系統會提示您升級Mono、Xamarin.iOS、Xamarin.Android和 Xamarin.Mac 以利用它。

使用 async & await

asyncawait 是與工作平行連結庫搭配運作的新 C# 語言功能,可讓您輕鬆地撰寫線程程式代碼來執行長時間執行的工作,而不會封鎖應用程式的主要線程。

async

宣告

關鍵詞 async 會放在方法宣告中(或位於 Lambda 或匿名方法上),以指出它包含可異步執行的程式代碼,也就是不要封鎖呼叫端的線程。

標記 async 的方法應該至少包含一個 await 運算式或語句。 如果方法中沒有 await 語句,則會以同步方式執行(與沒有 async 修飾詞相同)。 這也會導致編譯程式警告(但不會產生錯誤)。

傳回型別

異步方法應該傳回 TaskTask<TResult>void

如果方法未傳回任何其他值,請指定傳 Task 回型別。

指定 Task<TResult> 方法是否需要傳回值,其中 TResult 是所傳回的類型(例如 int,例如 , )。

void 回型別主要用於需要它的事件處理程式。 呼叫 void 傳回異步方法的程式代碼無法在 await 結果上執行。

參數

異步方法無法宣告 refout 參數。

await

await 運算子可以套用至標示為異步的方法內的Task。 這會導致 方法在該時間點停止執行,並等到工作完成為止。

使用 await 不會封鎖呼叫端的線程,而是將控制權傳回給呼叫端。 這表示不會封鎖呼叫線程,因此在等候工作時,使用者介面線程不會遭到封鎖。

當工作完成時,方法會繼續在程序代碼中的相同點執行。 這包括返回 try-catch-finally 區塊的 try 範圍(如果有的話)。 await 不能用於 catch 或 finally 區塊。

深入瞭解 await

例外狀況處理

異步方法內發生的例外狀況會儲存在工作中,並在工作發生時 await擲回。 這些例外狀況可以在 try-catch 區塊內攔截並處理。

取消

需要很長的時間才能完成的異步方法應該支援取消。 一般而言,會叫用取消,如下所示:

  • 物件 CancellationTokenSource 已建立。
  • 實例 CancellationTokenSource.Token 會傳遞至可取消的異步方法。
  • 呼叫 方法會要求 CancellationTokenSource.Cancel 取消。

工作接著會自行取消,並確認取消。

如需取消的詳細資訊,請參閱微調非同步應用程式 (C#)

範例

下載範例 Xamarin 解決方案 (適用於 iOS 和 Android),以查看行動應用程式中和 await 的運作範例async。 本節將更詳細地討論範例程序代碼。

撰寫異步方法

下列方法示範如何使用ed工作來撰寫方法await的程式代碼async

public async Task<int> DownloadHomepage()
{
    var httpClient = new HttpClient(); // Xamarin supports HttpClient!

    Task<string> contentsTask = httpClient.GetStringAsync("https://visualstudio.microsoft.com/xamarin"); // async method!

    // await! control returns to the caller and the task continues to run on another thread
    string contents = await contentsTask;

    ResultEditText.Text += "DownloadHomepage method continues after async call. . . . .\n";

    // After contentTask completes, you can calculate the length of the string.
    int exampleInt = contents.Length;

    ResultEditText.Text += "Downloaded the html and found out the length.\n\n\n";

    ResultEditText.Text += contents; // just dump the entire HTML

    return exampleInt; // Task<TResult> returns an object of type TResult, in this case int
}

請注意下列幾點:

  • 方法宣告包含 async 關鍵詞。
  • 傳回型別讓 Task<int> 呼叫程式代碼可以存取 int 此方法中計算的值。
  • return 語句是 return exampleInt; 整數物件, 方法傳 Task<int> 回的事實是語言改進的一部分。

呼叫異步方法 1

您可以在 Android 範例應用程式中找到此按鈕按下事件處理程式,以呼叫上述方法:

GetButton.Click += async (sender, e) => {

    Task<int> sizeTask = DownloadHomepage();

    ResultTextView.Text = "loading...";
    ResultEditText.Text = "loading...\n";

    // await! control returns to the caller
    var intResult = await sizeTask;

    // when the Task<int> returns, the value is available and we can display on the UI
    ResultTextView.Text = "Length: " + intResult ;
    // "returns" void, since it's an event handler
};

注意:

  • 匿名委派具有 async 關鍵詞前置詞。
  • 異步方法 DownloadHomepage 會傳回儲存在 sizeTask 變數中的 Task<int> 。
  • 程序代碼會等候 sizeTask 變數。 這是 暫停方法的位置,而且控制權會傳回呼叫程序代碼,直到異步工作在其自己的線程上完成為止。
  • 在方法的第一行上建立工作時,執行不會暫停,儘管工作是在該方法的第一行建立。 await 關鍵詞表示暫停執行的位置。
  • 當異步工作完成時,會從 await 行設定 intResult,並在原始線程上繼續執行。

呼叫異步方法 2

在 iOS 範例應用程式中,範例會以稍微不同的方式撰寫,以示範替代方法。 此範例不使用匿名委派, async 而是宣告指派的事件處理程式,就像一般事件處理程序一樣:

GetButton.TouchUpInside += HandleTouchUpInside;

接著會定義事件處理程式方法,如下所示:

async void HandleTouchUpInside (object sender, EventArgs e)
{
    ResultLabel.Text = "loading...";
    ResultTextView.Text = "loading...\n";

    // await! control returns to the caller
    var intResult = await DownloadHomepage();

    // when the Task<int> returns, the value is available and we can display on the UI
    ResultLabel.Text = "Length: " + intResult ;
}

一些重點:

  • 方法標示為 async ,但會傳 void 回 。 這通常只會針對事件處理程式完成(否則您會傳回 TaskTask<TResult> )。
  • await方法上的 DownloadHomepage 關鍵詞會直接指派給變數 (intResult),不同於先前的範例,我們使用中繼Task<int>變數來參考工作。 這是 控件傳回給呼叫端的位置,直到異步方法在另一個線程上完成為止。
  • 當異步方法完成並傳回時,執行會繼續執行, await 這表示會傳回整數結果,然後在UI小工具中轉譯。

摘要

使用 async 和 await 可大幅簡化在背景線程上繁衍長時間執行作業所需的程式代碼,而不會封鎖主要線程。 它們也可讓您在工作完成時輕鬆存取結果。

本檔提供 Xamarin.iOS 和 Xamarin.Android 的新語言關鍵詞和範例概觀。