Windows phone 8 JumpStart--Background Agents

  • 3908
  • 0
  • 2013-01-06

Background Agents

 

看此筆記文章之前提醒一下,

英文中的

schedule在此文中翻成 " 排程 "

agent在此文中翻成 " 代理 "

task在此文中翻成 " 任務/工作 "

IsolatedStorage在此文中翻成 " 隔離儲存區 "

朵拉盡量不用中文名,但若是有,造成閱讀困擾很抱歉。

 

範例學習重點:

Background Agents for Windows Phone

    ScheduledActionService

•多執行緒下的背景代理。

•檔案傳送task

•背景通知

 

Foreground Tasks

為了讓使用者有更良好的體驗,無論何時都保持一個應用程式在前景執行(且只能有一個唷!),才能持續回應使用者的動作,其他程式在記憶體中等待被選取:D,這樣也可以避免電量浪費。

可以透過長按返回鍵查看已開啟的應用程式,選取並且active。(Fast Application Switching module)

 

Background Agents

image

因為前景只能有一個應用程式active,所以我們可以透過Background Agents幫忙其他程式在背景執行。

雖然一個程式只能有一個background agent,但同一個agent可被兩個task執行,一個periodic,一個resource intensive。

以下是兩種不同任務的比較:

(1)Periodic task

短時間內的執行工作,通常用於獲取少量數據用。

例如: 動態磚的更新、位置追蹤。

(2)Resource intensive task

運行時間較長,通常用於使用者沒有主動使用手機時將大量數據同步到手機。

電源、網路、執行緒狀態有一定的規定下才會執行。

例如: 上傳下載資料、壓縮資料。

 

註記:

一次只能執行一種task,但可以有兩種Task case!

 

新增專案時就可以選擇有背景代理的專案唷:)

image

註記:

“scheduled task”不是指我們能決定背景代理什麼時候,或是否執行唷!

 

Agent和Task的分辨:

Agent是自己寫的code,在適當的時機決定該執行哪種Task。

Task則是scheduling object,跟 background agent 註冊,OS要在背景執行什麼功能。

註記:

background agent最好的使用是在動態磚更新,或是,從雲端抓取資料更新應用程式的data,這樣下次使用者開啟接收到的就是最新的資訊:)

 

Demo1:Location Logger

此範例簡單進行定位追蹤,background agent間隔性的在text log檔案存下手機的定位,即使log程序並未active。

image

LocationLogger是主要執行專案,而LocationLogTaskAgent則是背景執行專案負責追蹤位址。

註記:

當一個solution包含多個專案,則編譯完後每個專案會有各自的output dll檔案。

 

開始追蹤定位,按下重新整理後。

l1

ScheduledAgent.cs

註記:

ScheduledTask : 排程工作。

GeoCoordinateWatcher

 

返回到開始畫面,但並未停止追蹤定位,Location Tracker仍在背景執行。

l2

MainPage.xaml.cs

註記:

Background Task每15分鐘支援一次,但在debuggung狀態會改成每分鐘執行一次唷!

ScheduledActionService:管理排程工作。

 

 

Demo2: Debugging Tasks

此範例示範如何對背景Task偵錯。

註記:

背景task持續執行,即使Location Log application 仍在前景執行。

 

讓我們試著在ScheduledAgent.cs中SaveLogToIsolatedStorageFile()被呼叫的地方下中斷點。

 

可以看到因為現在範例仍然佔據前景作業,所以偵錯模式下,不能放置中斷點。

image

這是一般在程式執行狀態下試圖加上中斷點,會跳出的警告視窗。

image

 

當我們離開前景應用程式,Visual Studio仍在debug mode持續執行中。

此時中斷點就可以放置了!!

因此當程式進入背景專案執行時,便會被我們設置的中斷點擋下。

image

image

此時可以順便查看區域變數,發現是我們期望的Task內容以及想顯示的字串。

image

 

 

Demo 3 – File Transfer

 

File Transfer Tasks

和agent的運作方式不同,在此範例我們不需要分開的專案,我們只需要創建和管理transfer objects。

即使應用程式未在前景執行,Windows Phone 仍然允許應用程式透過HTTP,queue上傳或下載一個以上的檔案,並且在背景執行。(必須是Windows Phone OS 7.1 以後版本唷!)

 

BackgroundTransferRequest : 該物件代表一個transfer request,其內容包括:目標、檔案路徑、傳輸方法與現在傳輸的狀態。

BackgroundTransferService : 該物件用來初始化一個transfer request並且查詢或是移除transfer request。

補充:

觀念、物件完整介紹  Windows Phone 7 – Background File Transfer 不過這是WP7的範例,跟此範例還是有點不同唷:)

 

 

此範例主要示範在背景傳輸一個圖片檔案,因此我們利用返回鍵回到開始畫面,背景依然繼續傳輸檔案!

 

首先:

按下Add按鈕跳至AddBackgroundTransfer.xaml,按下Start Fetch開始在背景執行傳輸

rr2 rr6

 

 

執行Background Transfer流程:

1.使用命名空間

1
using Microsoft.Phone.BackgroundTransfer;

 

2.創建BackgroundTransferRequest

3.設定Request屬性

4.啟動Service管理Request (把Request加入Service)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
private void fetchFileButton_Click(object sender, RoutedEventArgs e)
{
//// (1) 檢查transfer request是否超過數量
if (BackgroundTransferService.Requests.Count() >= 5)
{
MessageBox.Show("此應用程序的背景文件傳輸請求的最大數量已超過。");
return;
}
 
 
//// (2) 創建新的transfer request
string transferFileName = filenameTextBlock.Text;
//將 URI 字串轉換成它的逸出表示。
Uri transferUri = new Uri(Uri.EscapeUriString(transferFileName), UriKind.RelativeOrAbsolute);
 
//創建新的transfer request
transferRequest = new BackgroundTransferRequest(transferUri);
 
// GET and POST 皆有,但是不支援FTP協定
transferRequest.Method = "GET";
 
//// (3) 設定request 1.下載目標位置 2.標籤 3.何種條件transfer可被使用
//從URI拿取檔案的名字,並且創建一個transfers目錄下的local URI。(放在隔離存取區內)
string downloadFile = transferFileName.Substring(transferFileName.LastIndexOf("/") + 1);
 
//因為下載的檔案必須指定儲存的實體位置,上傳也需要指定實體位置
//統一所有background tansfers使用的檔案路徑,必須存在於isolated storage的固定路徑:「/shared/transfers」之中
//建立URI
downloadUri = new Uri("shared/transfers/" + downloadFile, UriKind.RelativeOrAbsolute);
transferRequest.DownloadLocation = downloadUri;//設定下載目標儲存位置
 
//把抓取到的名字"picture.jpg"放入tag
transferRequest.Tag = downloadFile;
 
//設定允許傳遞的狀態
transferRequest.TransferPreferences = TransferPreferences.AllowCellularAndBattery;
 
 
//// (4) 啟動request
// 加入transfer request至BackgroundTransferService
try
{
BackgroundTransferService.Add(transferRequest);
}
catch (InvalidOperationException ex)
{
MessageBox.Show("Unable to add background transfer request. " + ex.Message);
}
catch (Exception)
{
MessageBox.Show("Unable to add background transfer request.");
}
 
 
// Navigate back
NavigationService.GoBack();
}

註冊監看狀態改變事件

1 2 3 4 5 6 7 8 9 10 11 12 13 14
private void InitialTransferStatusCheck()
{
UpdateRequestsList();
 
foreach (var transfer in transferRequests)
{
////監控傳輸狀態
transfer.TransferStatusChanged += new EventHandler<BackgroundTransferEventArgs>(transfer_TransferStatusChanged);
transfer.TransferProgressChanged += new EventHandler<BackgroundTransferEventArgs>(transfer_TransferProgressChanged);
ProcessTransfer(transfer);
}
 
...
}

 

5.監看Request現在狀態(Status)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
private void ProcessTransfer(BackgroundTransferRequest transfer)
{
switch (transfer.TransferStatus)
{
case TransferStatus.Completed:
 
// If the status code of a completed transfer is 200 or 206, the
// transfer was successful
if (transfer.StatusCode == 200 || transfer.StatusCode == 206)
{
//傳輸成功則移除request
RemoveTransferRequest(transfer.RequestId);
 
// 在此範例下載的檔案放在root隔離儲存區目錄下
using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication())
{
//取得使用者範圍內的隔離儲存區
string filename = transfer.Tag;
if (isoStore.FileExists(filename))
{
isoStore.DeleteFile(filename);//若已存在手動刪除下載的檔案
}
isoStore.MoveFile(transfer.DownloadLocation.OriginalString, filename);
}
}
else
{
//處理傳輸失敗。
RemoveTransferRequest(transfer.RequestId);
 
if (transfer.TransferError != null)
{
MessageBox.Show("傳輸失敗");
}
}
break;
 
 
case TransferStatus.WaitingForExternalPower:
WaitingForExternalPower = true;
break;
 
case TransferStatus.WaitingForExternalPowerDueToBatterySaverMode:
WaitingForExternalPowerDueToBatterySaverMode = true;
break;
 
case TransferStatus.WaitingForNonVoiceBlockingNetwork:
WaitingForNonVoiceBlockingNetwork = true;
break;
 
case TransferStatus.WaitingForWiFi:
WaitingForWiFi = true;
break;
}
}

 

6.監看Request進行狀況(Progress)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Tag}" Foreground="{StaticResource PhoneAccentBrush}" FontWeight="Bold"/>
<StackPanel Orientation="Horizontal">
<TextBlock Text="status: "/>
<TextBlock Text="{Binding TransferStatus}" HorizontalAlignment="Right"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="bytes received: "/>
<TextBlock Text="{Binding BytesReceived}" HorizontalAlignment="Right"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="total bytes: "/>
<TextBlock Text="{Binding TotalBytesToReceive}" HorizontalAlignment="Right"/>
</StackPanel>
</StackPanel>

註記:

此範例使用data binding的方式直接在xaml檔案中bind住要show出的訊息。

 

 

7.從Service手動移除Request(因為系統不會主動移除)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
private void RemoveTransferRequest(string transferID)
{
// 利用find方法找到要刪除的transfer file的特定ID
BackgroundTransferRequest transferToRemove = BackgroundTransferService.Find(transferID);
 
// 從service移除
try
{
BackgroundTransferService.Remove(transferToRemove);
}
catch (Exception e)
{
// Handle the exception.
}
}

 

這是傳輸尚未完成按下取消鍵(移除特定Request),或是按下clear all(移除全部Request)提示視窗。

R3

 

 

8.查看現在active的Request

1 2 3 4 5 6 7 8 9 10 11 12 13
private void UpdateRequestsList()
{
//為了確認舊的Request是否有部屬過了,避免記憶體濫用
if (transferRequests != null)
{
foreach (var request in transferRequests)
{
request.Dispose();
}
}
//沒被部屬過才啟用Service
transferRequests = BackgroundTransferService.Requests;
}

 

這是嘗試在Request傳輸過程中,新增一個相同的Request,所出現的警告視窗。

rr8

 

傳輸完成後view鍵可visable,按下可跳至ShowImage.xaml頁面察看完整圖片。

 rr5 rr7

 

 

 

最後,要注意TransferPreferences Enumeration ,使用者的限制習慣以及維護傳輸穩定性,記得做提醒用戶的處理唷:D

補充:

How to: Implement Background File Transfers for Windows Phone

 

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

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