非同步支援概觀
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。
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
async
和 await
是與工作平行連結庫搭配運作的新 C# 語言功能,可讓您輕鬆地撰寫線程程式代碼來執行長時間執行的工作,而不會封鎖應用程式的主要線程。
async
宣告
關鍵詞 async
會放在方法宣告中(或位於 Lambda 或匿名方法上),以指出它包含可異步執行的程式代碼,也就是不要封鎖呼叫端的線程。
標記 async
的方法應該至少包含一個 await 運算式或語句。 如果方法中沒有 await
語句,則會以同步方式執行(與沒有 async
修飾詞相同)。 這也會導致編譯程式警告(但不會產生錯誤)。
傳回型別
異步方法應該傳回 Task
、 Task<TResult>
或 void
。
如果方法未傳回任何其他值,請指定傳 Task
回型別。
指定 Task<TResult>
方法是否需要傳回值,其中 TResult
是所傳回的類型(例如 int
,例如 , )。
傳 void
回型別主要用於需要它的事件處理程式。 呼叫 void 傳回異步方法的程式代碼無法在 await
結果上執行。
參數
異步方法無法宣告 ref
或 out
參數。
await
await 運算子可以套用至標示為異步的方法內的Task。 這會導致 方法在該時間點停止執行,並等到工作完成為止。
使用 await 不會封鎖呼叫端的線程,而是將控制權傳回給呼叫端。 這表示不會封鎖呼叫線程,因此在等候工作時,使用者介面線程不會遭到封鎖。
當工作完成時,方法會繼續在程序代碼中的相同點執行。 這包括返回 try-catch-finally 區塊的 try 範圍(如果有的話)。 await 不能用於 catch 或 finally 區塊。
深入瞭解 await。
例外狀況處理
異步方法內發生的例外狀況會儲存在工作中,並在工作發生時 await
擲回。 這些例外狀況可以在 try-catch 區塊內攔截並處理。
取消
需要很長的時間才能完成的異步方法應該支援取消。 一般而言,會叫用取消,如下所示:
- 物件
CancellationTokenSource
已建立。 - 實例
CancellationTokenSource.Token
會傳遞至可取消的異步方法。 - 呼叫 方法會要求
CancellationTokenSource.Cancel
取消。
工作接著會自行取消,並確認取消。
如需取消的詳細資訊,請參閱微調非同步應用程式 (C#)。
範例
下載範例(適用於 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
回 。 這通常只會針對事件處理程式完成(否則您會傳回Task
或Task<TResult>
)。 await
方法上的DownloadHomepage
關鍵詞會直接指派給變數 (intResult
),不同於先前的範例,我們使用中繼Task<int>
變數來參考工作。 這是 控件傳回給呼叫端的位置,直到異步方法在另一個線程上完成為止。- 當異步方法完成並傳回時,執行會繼續執行,
await
這表示會傳回整數結果,然後在UI小工具中轉譯。
摘要
使用 async 和 await 可大幅簡化在背景線程上繁衍長時間執行作業所需的程式代碼,而不會封鎖主要線程。 它們也可讓您在工作完成時輕鬆存取結果。
本檔提供 Xamarin.iOS 和 Xamarin.Android 的新語言關鍵詞和範例概觀。