Windows phone 8 JumpStart--Async

原文:http://www.dotblogs.com.tw/dora0825/archive/2012/12/27/86024.aspx

Windows phone 8 JumpStart--Async


前言:

最新的WP8 SDK使用WinRT library,和windows 8 APP一樣,更加方便開發者了。

這次要來學習的KeyPoint !

1.利用await關鍵字暫停正在執行的方法,直到呼叫async。避免霸佔UI thread影響使用者體驗。

2.讓非同步Code表現像同步,不會有停止的感覺:)

3.實現 long-running tasks在背景執行!

 

Demo 1 –Async and Await

此範例示範 同步呼叫task、使用await進行非同步呼叫task、不使用await進行非同步呼叫task三種狀況,手機UI thread是否有反應。

首先創造一個long-running tasks 需要霸佔thread 3秒。

 

 

1. 同步呼叫

image

11

12345678
           
           
private void CallSync_Click ( object sender , RoutedEventArgs e )
{
Debug . WriteLine ( "=============== Call synchronously ===================" );
Debug . WriteLine ( "同步呼叫,執行ALongRunningOperation()的執行緒的ID: " + Thread . CurrentThread . ManagedThreadId );
int returnValue = ALongRunningOperation ();
Debug . WriteLine ( "回傳值: " + returnValue );
Debug . WriteLine ( "繼續執行UI thread" );
}
view raw gistfile1.cs hosted with ❤ by  GitHub

註記:

按下同步呼叫按鈕後,執行ALongRunningOperation(),因為thread被霸佔了,所以此時UI thread是被block住的,此時按下press Me! button,不會有任何反應。

 

2. 使用await進行非同步呼叫task

thread在背景執行ALongRunningOperation(),回傳值尚未回來,但UI thread並未被block住,所以此時按press Me! button是可以反應變色的:D

image image

 

 

 

這是因為 TPL (Task Parallel Library) 允許我們對同步的方法們,執行非同步的呼叫。

註記:

image

所以範例建立一個Task<int>方法去呼叫回傳值為int的ALongRunningOperation()。

12345678910
           
           
private async Task < int > ALongRunningOperationAsync ()
{
int returnValue = 0 ;
// Queue up the work to run on the Threadpool
await Task . Run (()=>
{
returnValue = ALongRunningOperation ();
});
return returnValue ;
}
view raw gistfile1.cs hosted with ❤ by  GitHub

12345678
           
           
private async void CallAsync_Click ( object sender , RoutedEventArgs e )
{
Debug . WriteLine ( "=============== 使用await非同步呼叫 ===================" );
Debug . WriteLine ( "使用await,執行ALongRunningOperation()的執行緒的ID: " + Thread . CurrentThread . ManagedThreadId );
int returnValue = await ALongRunningOperationAsync ();
Debug . WriteLine ( "回傳值: " + returnValue );
Debug . WriteLine ( "繼續執行UI thread" );
}
view raw gistfile1.cs hosted with ❤ by  GitHub

 

3. 不使用await進行非同步呼叫task

image

 

123456789
           
           
private void CallAsyncNoAwait_Click ( object sender , RoutedEventArgs e )
{
Debug . WriteLine ( "===============不使用await非同步呼叫 ===================" );
Debug . WriteLine ( "不使用await,執行ALongRunningOperation()的執行緒的ID: " + Thread . CurrentThread . ManagedThreadId );
//int returnValue =
ALongRunningOperationAsync ();
//Debug.WriteLine("回傳值: " + returnValue);
Debug . WriteLine ( "繼續執行UI thread" );
}
view raw gistfile1.cs hosted with ❤ by  GitHub

註記:

不使用await呼叫async方法是可以的,在我們不使用方法回傳值的時候,在此範例中output就不會等待async方法完成依然執行UI thread。但如果需要等待async方法的回傳值並且使用,則會產生錯誤。

image

結論:

此範例示範了同步跟非同步方法的呼叫方法以及使用await關鍵字去操作task在thread進行的順序,WinRT API提供開發者方便快速的方式去提升使用者體驗感,不會讓使用者覺得程式UI沒有反應,而感到困惑 :-)

 

 

 

Demo 2 – BackgroundWorker vs Task

如果有long-running工作想在背景執行,在WP8中有兩種方法可以達成。

12

1. 執行背景工作

BackgroundWorker。

14

12345678910111213141516171819
           
           
private void LaunchBGWButton_Click ( object sender , RoutedEventArgs e )
{
Debug . WriteLine ( "(BGW)呼叫者執行緒ID: " + Thread . CurrentThread . ManagedThreadId );
 
BackgroundWorker bgw = new BackgroundWorker ();
bgw . RunWorkerCompleted += (( s , a ) =>
MessageBox . Show ( "BGWButton----工作已完成, 結果: " + ( int ) a . Result )
);
bgw . DoWork += (( s , a ) =>
{
Debug . WriteLine ( "(BGW)背景工作者執行緒ID: " + Thread . CurrentThread . ManagedThreadId );
// Simulate some long running work
Thread . Sleep ( 5000 );
// Return the result
a . Result = 1234 ;
});
// Now start execution
bgw . RunWorkerAsync ();
}
view raw gistfile1.cs hosted with ❤ by  GitHub

註記:

BackgroundWorker.DoWork 事件

 

Task比BackgroundWorker更為簡潔整齊

15

12345678910111213141516
           
           
private async void LaunchTaskButton_Click ( object sender , RoutedEventArgs e )
{
Debug . WriteLine ( "(Task)呼叫者執行緒ID: " + Thread . CurrentThread . ManagedThreadId );
 
int result = await Task . Factory . StartNew < int >(() =>
{
Debug . WriteLine ( "(Task)背景工作者執行緒ID: " + Thread . CurrentThread . ManagedThreadId );
// Simulate some long running work
Thread . Sleep ( 5000 );
// Return the result
return 4321 ;
}
);
 
MessageBox . Show ( "TaskButton----工作已完成, 結果: " + result );
}
view raw gistfile1.cs hosted with ❤ by  GitHub

註記:

TaskFactory.StartNew

 

2.有進度回報的背景工作

BackgroundWorker支援Progress reports。

bp

12345678910111213141516171819202122232425
           
           
private void LaunchBGWwithProgressButton_Click ( object sender , RoutedEventArgs e )
{
...
bgw . WorkerReportsProgress = true ;
...
bgw . ProgressChanged += (( s , a ) =>
{
// Progress Indicator value must be between 0 and 1
SystemTray . GetProgressIndicator ( this ). Value = ( double ) a . ProgressPercentage / 100.0 ;
}
);
bgw . DoWork += (( s , a ) =>
{
// 模擬一個long running work
for ( int i = 0 ; i < 10 ; i ++)
{
Thread . Sleep ( 500 );
// Report progress as percentage completed
bgw . ReportProgress ( i * 10 );
}
...
});
...
}
view raw gistfile1.cs hosted with ❤ by  GitHub

註記:

(1)設定BackgroundWorker的WorkerReportsProgress為true。

(2)針對ProgressChanged event 做處理。

(3)在BackgroundWorker的DoWork中呼叫BackgroundWorker.ReportProgress方法拿取進度百分比。

 

Task

13

123456789101112131415161718192021222324
           
           
private async void LaunchTaskwithProgressButton_Click ( object sender , RoutedEventArgs e )
{
ShowandClearProgressIndicator ();
 
IProgress < int > progressReporter = new Progress < int >(( percentComplete ) =>
{
// 進度指針數值範圍在0~1
SystemTray . GetProgressIndicator ( this ). Value = ( double ) percentComplete / 100.0 ;
});
int result = await Task . Factory . StartNew < int >(() =>
{
// Simulate some long running work
for ( int i = 0 ; i < 10 ; i ++)
{
Thread . Sleep ( 500 );
// Report progress as percentage completed
progressReporter . Report ( i * 10 );
}
// Return the result
return 4321 ;
}
);
...
}
view raw gistfile1.cs hosted with ❤ by  GitHub

註記:

因為Task沒有支援Progress reports,所以在此範例Task code並不會比較簡潔。

 

 

 

3.消除背景工作

BackgroundWorker支援Cancellation。

bcappb

1234567891011121314151617181920212223
           
           
private void LaunchBGWwithCancelButton_Click ( object sender , RoutedEventArgs e )
{
...
//在此bgwCancel是private
bgwCancel . WorkerSupportsCancellation = true ;
...
bgwCancel . DoWork += (( s , a ) =>
{
// 模擬一個long running work
for ( int i = 0 ; i < 10 ; i ++)
{
...
// check是否取消背景工作?
if ( bgwCancel . CancellationPending )
{
a . Cancel = true ;
return ;
}
}
...
});
...
}
view raw gistfile1.cs hosted with ❤ by  GitHub

註記:

(1)設定BackgroundWorker的SupportsCancellation為true。

(2)在RunWorkerCompleted事件處理中檢查事件參數的Cancelled屬性確定工作是否完成或取消。

 

Task須透過OperationCanceledException。

tcappt   

 

1234567891011121314151617181920212223242526272829303132
           
           
private async void LaunchTaskwithCancelButton_Click ( object sender , RoutedEventArgs e )
{
ShowandClearProgressIndicator ();
 
cancellationTokenSource = new CancellationTokenSource ();
var cancellationToken = cancellationTokenSource . Token ;
//自行定義進度回報的提供者
//間歇性的呼叫 Progress<T>.Report,回傳完成比例
...
 
try
{
int result = await Task . Factory . StartNew < int >(() =>
{
// 模擬一個long running work
for ( int i = 0 ; i < 10 ; i ++)
{
...
// check是否取消背景工作?
cancellationToken . ThrowIfCancellationRequested ();
}
...
}, cancellationToken );
 
MessageBox . Show ( "TaskwithCancelButton----工作已完成, 結果: " + result );
}
catch ( OperationCanceledException ex )
{
MessageBox . Show ( "Task取消。" );
}
SystemTray . GetProgressIndicator ( this ). IsVisible = false ;
}
view raw gistfile1.cs hosted with ❤ by  GitHub

註記:

(1)建立一個CancellationTokenSource,拿取其Token屬性當作Task.factory.StartNew的第二個參數。

(2)在外部呼叫想取消task時,事實上是呼叫CancellationTokenSource的Cancel method。(按下AppBar的取消鍵)

(3)在long running work中間歇性呼叫CancellaionToken.ThrowIfCancellationrequested() method,偵測是否有task取消的要求。

(4)task的取消要求會產生OperationCanceledException被caught的例外狀況。

image

註記:

執行task任務時,按下app bar的取消鍵,VS會停止認為是無法處理的例外,但只是背景執行緒無法處理,事實上會編排回呼叫者,並且丟回到原來的執行緒。

程式停止沒關係,按繼續執行(> 或是 F就可以了唷!

 

最後:

有關WP8 JumpStart詳細課程內容都可以上Windows Phone Developer Blog唷。

如有任何問題、錯誤,可在下面留言,謝謝您的指教。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值