Windows 8 Metro 編程相對於Windows phone 和 Silverlight 最大的不同點之一就是大量的使用了非同步API,而且這些API通常沒有相對應的同步API,因此我們需要確保瞭解如何在Metro風格應用中使用非同步API。
使用非同步API時不可避免的會碰到兩個關鍵詞:await 和 async,下面我們舉例說明非同步API的優勢和具體的用法。
非同步API一般是需要較長時間才能返回結果或者完成的(例如:I.O.操作)。假設我們在點擊一個Button之後,程式會讀取一個比較大的本地檔案。
1. 如果用同步的方式讀取,那麼在返回讀取結果之前的這段時間內,你得程式不能同時進行其他相應,比如使用者再次的點擊,也就是說你得程式是阻塞狀態。
2. 如果換成非同步作業就不同了,程式在執行到這一行代碼時,應用會臨時退出時間處理常式,它可以在等待返回結果的過程中同時處理其他的使用者相應,直到成功返回結果後繼續進行下面的代碼。
(經Damon.Tian提醒,這裡代碼做了修改,傳回型別應為Task<bool>)
private async Task<bool> IsSuccess (string fileName, StorageFolder folder){ var file = await folder.CreateFileAsync(fileName, CreationCollisionOption.OpenIfExists); string tempString = "Wow!";
return true;}
這就是讀取檔案的API,在這裡使用的await關鍵字,代表調用非同步介面並等待返回結果後才執行後面的代碼(記住這句話,後面會講到)。
再看看這個函數在定義時用了一個關鍵字:async,這是因為在此函數中至少有一個地方用了await關鍵字,那麼這個函數就必須定義為async。在外面調用這個函數的時候也就可以用await關鍵字了,例如:
bool result = await IsSuccess(fileName, folder);
同樣的,上面這行代碼所在的函數,也必須聲明async關鍵字。
接下來,問題來了,這兩個關鍵字是不是必須要寫的呢?可不可以不用?答案是,可以。
如果在調用非同步API時沒有用到await關鍵字,也是可以的。
我們還拿上面的function舉例,如果寫成下面這樣也是可以的,但是在編譯的時候會產生一個警告:沒有用await關鍵字。
var file = folder.CreateFileAsync(fileName, CreationCollisionOption.OpenIfExists);
那這兩種寫法有什麼不同呢?答案是:代碼的執行順序有了改變,而且返回結果的類型也變了。
如果調用非同步API時沒有用await,那麼在執行非同步作業的時候,程式是不會等待API返回結果再執行下面的代碼,而是直接執行下面的代碼:
也就是說,如果代碼變成下面這個樣子,那麼file還沒有被成功賦值時(CreateFileAsync函數還未返回結果時),tempString就已經被賦值了。
(如果不帶await 這裡返回的file不再是StorageFile類型而是 IAsyncOperation<StorageFile>類型)
private async Task<bool> IsSuccess (string fileName, StorageFolder folder){ var file = folder.CreateFileAsync(fileName, CreationCollisionOption.OpenIfExists); string tempString = "Wow!";
return true;}
例如:應用中一般都會有彈出框彈出警告,例如:假設我們寫一個demo,發布博文成功後用彈出系統警告框,下面是公用函數:彈出系統警告框
public async static void Alert(string message, string title = "") { MessageDialog dlg = new MessageDialog(message, title); await dlg.ShowAsync(); }
代碼一:
Alert("您還未登陸。");Alert("請登入!");
代碼二:
await Alert("您還未登陸。");await Alert("請登入!");
以上兩段代碼執行的結果不同,第一段代碼會連續彈出兩個彈出框,先彈出“您還未登入。”,然後彈出“請登入!”,第二個彈出框在第一個彈出框的上面。
代碼二會先彈出第一個警告:未登入,使用者點擊“確定”按鈕關閉彈出框後,才會彈出第二個彈出框。
另外需要注意的是:
await無法用在類似lock塊代碼中:
lock(tempString){ //這裡不能用await}
Lamda運算式可以這樣寫
this.Loaded += async (sender, args) =>
{
await ...
};
以上是我的簡歷,有任何問題或不同建議,歡迎提出,大家一起討論,更好的鋪平win8開發之路!
我的微博:http://weibo.com/345169632 介是為什麼
我的部落格:http://www.cnblogs.com/lihaiyin