- 本篇針對 Sweetshot 這個 App 的開發經驗做分享 -

(Develop with Windows Phone SDK 8.0 on Visual Studio 2013 Ultimate)

要寫手機的 App, 免不了要用到多條執行緒..  原因為何呢?

記得以前在寫 Web application 的時候,要執行 Server-Side 的判斷都要 send request to server 然後等 server postback to client,依據要做的處理多寡一來一往可能要等數秒到數十秒鐘,在等待期間使用者是不能夠和頁面有其他 UI 互動。後來開始流行 ajax (Asynchronous JavaScript and XML) 非同步開發技術除了減少頻寬的浪費以外,主要是可以避免 ui blocking 和更新頁面時的閃爍並提升使用者的使用經驗 (UX)。

手機上的 main thread (主執行緒) 也稱作為 ui thread,UI相關的操作只能夠在這條執行緒上面操作,否則在 WP 手機上會發生 cross-thread exception (記得在 iOS 或 Android 也有同樣的規定)。

何時會需要開第二條甚至第三條執行緒呢?

(其實很多控制項背後的運作就有用到多執行緒,譬如當你給 Image control 的 Source 設為一個圖片的網址,Image control 會在另一條執行緒抓取這張圖片最後呈現在 UI 上)

1. 執行等待時間很長的工作:譬如 http request 的時候

2. 執行需要占用 CPU 許多效能的工作:譬如需要處理大量資料的時候 (新增資料,刪除資料),影像處理

有哪些方式可以實作多執行緒?

BackgroundWorker

BackgroundWorker 的特色是有提供 ProgressChangedEventHandler,方便監控工作處理的進度,而在這個 event handler 裡面就可以去更新畫面資訊,例如:目前下載檔案的百分比資訊。

官方教學參考:

http://msdn.microsoft.com/en-us/library/windowsphone/develop/cc221403(v=vs.105).aspx

System.Threading.Thread

這個方法我會用在不需要知道處理的進度與結果的情況,譬如與伺服器同步後 delete sweetshot app client 端所儲存的孤兒照片(可能是另一半已經把照片刪除了,所以該照片會變成多餘的檔案儲存在 app 的空間中)。

使用方式為 :

new Thread(() =>
{

    //做需要做的背景工作

}).Start();

Async and Await

在 Windows Phone 很多官方的 API 中會看到方法名稱的結尾為 xxxxAsync,就必須要使用 async and await 的模式。

例如 Sweetshot 中取得照片的方法 :

public async Task LoadDataAsync(xxx)
{

    PhotoListResult photoList = await HttpUtil.GetShotsAsync(xxx);

}

public static async Task<PhotoListResult> GetShotsAsync(xxx)
{
    var pList = getInitParameterList();
    pList.Add(xxx);

    JToken token = await SimpleApiCallAsync("xxx", pList, HttpMethod.Get);;

    return JsonConvert.DeserializeObject<PhotoListResult>(token.ToString());
}

(為保護 Sweetshot 的 API, 以上關鍵參數名稱以 xxx 代替)

注意事項:

1. 方法中只要有用到 await,方法名稱中就必須加入 async 關鍵字否則編譯就會失敗,反之編譯器應該會給使用者一個警告,提醒方法名稱中有 async 但是方法裡面沒有 await 關鍵字。

2. 假如是非同步處理的方法,方法的命名原則為名稱結尾加上 Async,如此使用這個方法的人可以從字面上知道這是一個 async and await 非同步的方法。

3. 可以依據需求包很多層的 async and await,以上的範例至少包了4層,運作流程如下:

- UI 程式碼中呼叫 LoadDataAsync

- LoadDataAsync 呼叫 GetShotAsync

- GetShotAsync 呼叫 SimpleApiCallAsync,取得 server 回覆的 json 並回傳 PhotoListResult 物件

- LoadDataAsync 取得 PhotoListResult 後更新 Binding 到 DataContext 的 photoListResult 物件

- 因為 PhotoListResult 有採用 INotifyPropertyChanged 介面,因此當 photoListResult 物件被更新的時候便會通知有被 Binding 到的相關 UI 做更新

- UI 程式碼執行後續需要執行的工作

官方教學參考:

http://msdn.microsoft.com/en-us/library/vstudio/hh873191.aspx

http://developer.nokia.com/Community/Wiki/Asynchronous_Programming_For_Windows_Phone_8

如何在非主執行緒中更新 UI 資訊?

假如你的程式有發生 cross thread exception 這個錯誤,應該就是你在非 ui thread 中要去更新 ui,而在非 ui thread 要更新 ui 的方法如下:

1. 使用 Deployment.Current.Dispatcher 來取得目前的 Dispatcher

2. 透過 Dispatcher 執行 BeginInvoke 方法

Dispatcher.BeginInvoke(() => {
     
});

官方文件參考:

http://msdn.microsoft.com/en-us/library/cc190259(v=vs.95).aspx

以上的分享,可能並非最佳和完美的,但是應該可以給剛入門的朋友們一個初步的 concept,假如有任何問題或者是有更好的做法也請不吝分享與指教。

------------------

Thinking.jpg 

筆者:Alan Feng

大學由資管系畢業後便投入職場,先後擔任程式設計師,系統設計師,系統分析師,專案管理師等職務。

曾服務於資訊服務業,筆電代工設計公司,和遊戲公司的專案管理師/程式設計師~目前在廣告行銷公關業擔任系統分析師。

持有國際 PMP 證照並持續努力累積社會大學的經驗中。


arrow
arrow

    Alan Feng 發表在 痞客邦 留言(0) 人氣()