Windows Phone 7 – Background File Transfer
學了一陣子關於Background Agent的運用後,感覺WP7在Background上的處理,讓開發人員學習非常容易,
但有些觀念可能需要自己多花點時間來看,以免在送審程式時花了不少的時間成本。
今天要介紹的是Background File Transfer,這是WP7.1 SDK提供的另一個Backgrund Agent,適合使用的情境
可想而知:運用於傳輸大量檔案、背景與Server端交換資訊等。因此,往下將針對重點部分一一說明:
〉Microsoft.Phone.BackgroundTransfer:
WP7.1 SDK提供應用程式佇列一至多個檔案進行上傳/下載,並且讓任務可在背景環境下繼續執行,甚至是該
應用程式已長時間不在前景執行,另外該API也提供擷取、查詢目前file transfer運行的狀態,讓end user可以了
解目前的存取狀態。這些功能在Microsoft.Phone.BackgroundTransfer裡都能找到,接著往下介紹二個重要元件:
A. BackgroundTransferRequest與BackgroundTransferService:
A-1. BackgroundTransferRequest:
該物件代表一個transfer request,其內容包括:目標、檔案路徑、傳輸方法與現在的傳輸狀態。
另外,當transfer request下載完成觸發completed事件時,記得呼叫background transfer service將這個
transfer request進行remove,因為系統必不會自動把它移去。
重點屬性說明:
Name | Description |
DownloadLocation | 取得/設定request檔案下載後要儲存的local path。可搭配建構子一起設定。 |
Headers | 取得request的HTTP headers集合(Dictionary)。 |
Method | 取得/設定request使用的HTTP Method。 |
TransferPreferences | 取得/設定何種條件下transfer可以被使用,屬於列舉值:TransferPreferences Enumeration。可參考[補充]的說明。 |
TransferStatus | 取得transfer的狀態。可配合BytesReceived與BytesSent擷取進度時使用。 |
TransferError | 如果transfer執行了completed,TransferError通常是null。相反的,不為null則代表有錯誤發生。 |
另外,二個重要的事件:TransferProgressChanged與TransferStatusChanged留到範例來說明。
A-2. BackgroundTransferService:
該物件用於初始化一個新的transfer、查詢或管理已存在的file transfers。其任務為控制所有的transfer物件,
然而,BackgroundTransferRequest.Method僅支援HTTP與HTTPS,尚不支援FTP的協定,所以目前可以透過
GET/POST上傳或下載檔案。
重點屬性說明:
Name | Description |
Requests | 取得向BackgroundTransferServicec中所有啟動的transfer requests。其角色與ScheduledActionService中的GetActions很相似。 |
Add | 增加background transfer request至佇列中。 |
Find | 透過指定的ID(RequestId)去企圖取回特定的background transfer reqeust。 |
Remove | 透過指定的ID(RequestId)去企圖移除特定的background transfer reqeust。 |
了解了BackgroundTransferService的角色之後,要特別注意的是:
a-2-1. 每一個應用程式只能有5個request在給定的時間內。
a-2.2. 企圖增加超過5個request時,系統會自動發出Exception。
a-2-3. 如果要移除佇列中的request,請透過Remove的方法,該方法移除成功後會觸發Completed的事件。
C. Background Transfer Policies (Background Transfer基本守則):
C-1. File System Restrictions(檔案路徑使用條件):
所有的background trasnfers都需要有一個 local file path(實際本機路徑)。下載檔案需要指定要儲存的實際位置;
上傳檔案需指定要從那一個實際位置將檔案上傳,因此,所有的background tansfers使用的檔案路徑,必須存在於
isolated storage的固定路徑:「/shared/transfers」之中,該資料表是在程式被安裝至設備後,自動產生出來的,
如果自己手動刪除或更名了,必須再重建一個相同名稱的資料夾,才能初始化所有的transfers物件。
另外,可在/shared/transfers資料夾下建構需要檔案結構,這是合法的,但如果使用transfers時使用的是非特定的路徑,
那transfer將無法被初始化則會出現exception。
C-2. Sizes(檔案大小):
最大上傳檔案大小 | 5 MB |
在行動網路,最大下載檔案大小 | 20 MB 如果檔案超過限制,TransferPreferences屬性會自動轉變成AllowBattery,這將變成要求於Wi-Fi環境下才能進行傳輸。 |
在Wi-Fi,沒有外接電源,最大下載檔案大小 | 100 MB 如果檔案超過100 MB,需設定TransferPreferences屬性為"None",否則傳輸會失敗。如果應用時不確定傳輸檔案的大小時,建議設定成None可以確保傳輸程序不會被拒絕。 |
C-3. Limits(限制):
每個應用程序的最大未完成請求佇列量。(包括:active與pending的請求) | 5 由於傳輸完成後,傳輸請求並不會被自動移除,需要透過Remove(BackgroundTransferRequest)去除存在佇列中已完成的項目。 |
設備上跨所有應用程序的目前最大傳輸程序 | 2 當前最多只有二個Background File Transfer在運作。 |
設備上跨所有應用程序的最大佇列傳輸程序 (Maximum queued transfers across all applications on the device) |
500 |
每個Requeset的HTTP headers最大數量 | 15 |
HTTP headers的最大容量 | 16 KB each |
另外,在使用HTTP headers時,有幾個保留字是不可以使用於BackgroundTransferRequest,如下:
「If-Modified-Since」、「If-None-Match」、「If-Range」、「Range」與「Unless-Modified-Since」。
C-4. Policies(守則):
‧background file transfer不支援在「non-simultaneous voice」與「2G, EDGE, Standard GPRS」環境使用。
=>因此,background file transfer只支援在Wi-Fi、3G(或更快速)的網路環境。
‧當檔案大小超過5 MB時,HTTP headers中的「content-length」與「range」 是必要存在的。Server端應該
永遠在response中回傳content-length的值。如果不這樣做,可能會造成嚴重的傳輸效能退化。
C-5. Slow Transfer(較慢的速度):
‧如果網路的速度低於下列的速度,傳輸任務會被paused(暫停)與retried(重新連線):
=> 3G (50 kbps);Wi-Fi(100 kbps)
〉範例說明:
該範例為撰寫一個透過手機下載圖示至本機IIS裡。看起來非常容易吧,因為在前年我已經有寫過一個
下載檔案的程式範例:<Windows Phone 7 – 下載檔案至Isolated Storage>,當時是使用WebClient實作Download的功能,
但它只能在程式執行時使用,今天範例則是要讓它也能在背景執行。
a. 程式啟動後,先檢查「/shared/transfers」是否存在;
1: private void Initialization()
2: {
3: using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication())
4: {
5: //確認特定的目錄是否存在,如果沒有則需要建立。
6: if (!isoStore.DirectoryExists("/shared/transfers"))
7: {
8: isoStore.CreateDirectory("/shared/transfers");
9: }
10: }
11: }
b. 建立background transfer request物件,並且加上判斷是否已有5個transfer request出現在佇列中;
1: private void CreateBgTransferRequest()
2: {
3: //檢查目前該應用程式的Background transfer service佇列中是否有5個transfer request了。
4: if (BackgroundTransferService.Requests.Count() >= 5)
5: {
6: MessageBox.Show("此應用程序的背景文件傳輸請求的最大數量已超過。");
7: return;
8: }
9: Uri tUri = new Uri("http://www.zbeauty.cn/UpLoadFile/Image/2011/9/5/151515157693767.jpg", UriKind.Absolute);
10: Uri tLocalUri = new Uri("/shared/transfers/151515157693767.jpg", UriKind.RelativeOrAbsolute);
11:
12: BackgroundTransferRequest tRequest = new BackgroundTransferRequest(tUri, tLocalUri);
13: tRequest.Method = "GET";
14: tRequest.Tag = "151515157693767.jpg"; //作為識別用
15:
16: //設定TransferPreferences 為AllowCellular,有外接電源,只要Cellular或wifi就可以下載
17: tRequest.TransferPreferences = TransferPreferences.AllowCellular;
18:
19: //註冊要關心的事件
20: tRequest.TransferProgressChanged += new EventHandler<BackgroundTransferEventArgs>(tRequest_TransferProgressChanged);
21: tRequest.TransferStatusChanged += new EventHandler<BackgroundTransferEventArgs>(tRequest_TransferStatusChanged);
22:
23: try
24: {
25: //加入佇列
26: BackgroundTransferService.Add(tRequest);
27: }
28: catch (InvalidOperationException ex)
29: {
30: MessageBox.Show("Unable to add background transfer request. " + ex.Message);
31: }
32: catch (Exception)
33: {
34: MessageBox.Show("Unable to add background transfer request.");
35: }
36: }
c. 監控狀態的改變,成功後移除background tansfer request;
1: void tRequest_TransferStatusChanged(object sender, BackgroundTransferEventArgs e)
2: {
3: //用於更新畫面的圖示
4: }
5:
6: void tRequest_TransferProgressChanged(object sender, BackgroundTransferEventArgs e)
7: {
8: switch (e.Request.TransferStatus)
9: {
10: case TransferStatus.Completed:
11: if (e.Request.StatusCode == 200 || e.Request.StatusCode == 206)
12: {
13: //代表下載成功了,要手動將它移除
14: RemoveTransferRequest(e.Request.RequestId);
15: }
16: else
17: {
18: //代表下載失敗了,一定要手動將它移除
19: RemoveTransferRequest(e.Request.RequestId);
20:
21: if (e.Request.TransferError != null)
22: {
23: Dispatcher.BeginInvoke(() =>
24: {
25: MessageBox.Show(e.Request.TransferError.Message);
26: });
27: }
28: }
29: break;
30: case TransferStatus.WaitingForExternalPower:
31: break;
32:
33: case TransferStatus.WaitingForExternalPowerDueToBatterySaverMode:
34: break;
35:
36: case TransferStatus.WaitingForNonVoiceBlockingNetwork:
37: break;
38:
39: case TransferStatus.WaitingForWiFi:
40: break;
41: }
42: }
43:
44: private void RemoveTransferRequest(string transferID)
45: {
46: // Use Find to retrieve the transfer request with the specified ID.
47: BackgroundTransferRequest transferToRemove = BackgroundTransferService.Find(transferID);
48: // Try to remove the transfer from the background transfer service.
49: try
50: {
51: BackgroundTransferService.Remove(transferToRemove);
52: }
53: catch (Exception e)
54: {
55: // Handle the exception.
56: }
57: }
d. 執行下載與產生圖示;
1: private void mbtnDonwload_Click(object sender, EventArgs e)
2: {
3: //執行增加background transfer request
4: CreateBgTransferRequest();
5: }
6:
7: //觸發事件是Background transfer request在completed時。
8: private void LoadImage(string pLocalPath)
9: {
10: //將isolated storage中儲存的圖片載出來
11: var isoFile = IsolatedStorageFile.GetUserStoreForApplication();
12: using (var imageStream = isoFile.OpenFile(
13: pLocalPath, FileMode.Open, FileAccess.Read))
14: {
15: var imageSource = PictureDecoder.DecodeJpeg(imageStream);
16: imgView.Source = imageSource;
17: }
18: }
e. 執行畫面;
[補充]
〉TransferPreferences Enumeration:
Member Name | Description |
None | (預設值) 只有在當設備使用外接電源與具有Wi-Fi連線,才允許進行傳輸。 |
AllowCellular | 當設備使用外接電源,具有Cellular或Wi-Fi連線時,允許傳輸。 |
AllowBattery | 當設備使用Wi-Fi連線,具有電池或外接電源時,允許傳輸。 |
AllowCellularAndBattery | 當設備使用電池或外接電源,具有Wi-Fi或Cellular連線時,允許傳輸。 |
上述的說明,如果在實作應用時,能夠預期用戶下載的資料大小與環境條件,建議還是按照上述的設定去提示用戶,
一來可以確保用戶得知限制的提示,二來可以讓程式運作更接近用戶的使用習慣與穩定性。
======
以上是針對Background File Transfer的介紹,該功能學習起來跟Background Agent系列的其他元素相似,
重點在於注意Background的限制,其他的處理就跟一般HttpRequest或WebClient的使用接近了。另外,
在msdn上也有提供在撰寫background Agent的應用時,建議使用實體設備進行測試比較接近實際結果。
送審時,別忘記先對一下「Additional Requirements for Specific Application Types」的限制與要求喔。
References:
‧Background File Transfers Overview for Windows Phone
‧Background File Transfer Best Practices for Windows Phone
‧How to: Implement Background File Transfers for Windows Phone (重要)
‧Background File Transfer Best Practices for Windows Phone (必讀,學習後必看的內容)
‧Background Transfer Service Sample
‧Microsoft.Phone.BackgroundTransfer
‧31 Days of Mango | Day #26: Background File Transfer
‧Windows Phone 7 Background File Transfer
‧Leveraging Background Services and Agents in Windows Phone 7 (Mango)
‧Additions in the Windows Phone SDK 7.1 - Background File Transfers
‧[WP7.1] Background File Transfer Service