內容預告:
- Windows Phone 任務管理
- 用后台代碼實現多任務
- 在Visual Studio中創建任務
- 文件傳輸任務
- 后台提醒
- 后台音樂播放
前台任務:一般來說,一個Windows Phone應用程序運行在前台時,它可以與用戶直接交互,但同時只能有一個程序運行在前台,是為了保證性能和電量。
后台代理:Windows Phone應用程序可以開啟一個后台代理,類型可以是定期執行或資源密集型或兩者兼俱型,但每個程序只能有一個后台代理。后台代理和前台程序運行在后台不是一回事,后台代理只能做有限的事情。
后台代理的限制:在Windows Phone系統上同時可運行后台代理的數量有限的,且只有在條件允許的情況下操作系統才把CPU的控制權交給后台代理,省電模式下不能運行,用戶可以自己關閉。
代理和任務:一個任務是操作系統管理的在某個約定的時間執行的,有定期執行或資源密集型兩種。一個后台代理是真正要執行的代碼,代理代碼從BackgroundTask派生,是計划任務代理項目的一部分。
定期任務:大約每30分鍾執行一次,每次大約25秒,內存使用量小於6MB,兩次crash連續后會取消,同時活躍的任務數量有限制,適用於定位跟蹤,后台輪詢,磁貼更新。
資源密集型任務:外接電源時,電量大於90%,WiFi,鎖屏狀態,可連續運行10分鍾,內存使用量小於6MB,兩次crash連續后會取消,適合同步服務,解壓縮,壓縮數據庫。
兼俱型任務:可以用一個后台任務類運行兩種任務,系統會根據上下文判斷執行合適的任務。
后台代理功能:
定位跟蹤器:用后台代理以日志文件的方式存儲有規律地存儲手機的坐標,代理會在日志程序沒有焦點的時候更新位置數據。
創建后台代理:
連接代理項目:船長日志項目引用了一個定位任務項目的輸出,前台程序不直接引用任何代理類的對象或類。
后台代理代碼:必須實現OnInvode函數,它完成時會通知運行時系統。
namespace LocationLogTaskAgent { public class ScheduledAgent : ScheduledTaskAgent { protected override void OnInvoke(ScheduledTask task) { //TODO: Add code to perform your task in background NotifyComplete(); } } }
與后台代理共享數據:通過獨立存儲
protected override void OnInvoke(ScheduledTask task) { string message =""; string logString = ""; if (LoadLogFromIsolatedStorageFile() { message = "Loaded"; } else { message = "Initialised"; } ... }
並發數據存儲:用互斥量(Mutex)保護存儲文件,保證釋放mutex。
public bool LoadLogFromIsolatedStorageFile() { mut.WaitOne(); // Wait until it is safe to enter try { // read the file here return true; } catch { LogText = ""; return false; } finally { mut.ReleaseMutex(); // Release the Mutex. } }
鈎選定位能力:
獲取手機位置:通過GeoCoordinateWatcher類提供位置信息,在后台代理中使用Position,其每15分鍾更新一次。
protected override void OnInvoke(ScheduledTask task) { ... GeoCoordinateWatcher watcher = new GeoCoordinateWatcher(); watcher.Start(); string positionString = watcher.Position.Location.ToString() + System.Environment.NewLine; ... }
存儲手機位置:
protected override void OnInvoke(ScheduledTask task) { ... logString = logString + timeStampString + " " + positionString; SaveLogToIsolatedStorageFile (); ... }
顯示通知:后台任務可以彈出toast提醒,如果用戶點擊toast,可以啟動程序,Toast消息會在程序激活后消失。
protected override void OnInvoke(ScheduledTask task) { ... logString = logString + timeStampString + " " + positionString; SaveLogToIsolatedStorageFile (); ... }
安排一個后台代理:
PeriodicTask t; t = ScheduledActionService.Find(taskName) as PeriodicTask; bool found = (t != null); if (!found) { t = new PeriodicTask(taskName); } t.Description = description; t.ExpirationTime = DateTime.Now.AddDays(10); if (!found) { ScheduledActionService.Add(t); } else { ScheduledActionService.Remove(taskName); ScheduledActionService.Add(t); }
調試后台任務:我們可以強制服務啟動代理,因為30分鍾才能執行一次太煩人了。
#if DEBUG_AGENT ScheduledActionService.LaunchForTest(taskName, TimeSpan.FromSeconds(60)); #endif
Tips:
- 經常續訂,因為后台任務只能持續2周有效。
- 不實現后台代理的臨界功能,因為用戶可能禁用,系統也可能因為電量原理掛起程序。
- 如果需要穩定的更新磁貼或Toast消息,考慮用推送。
文件傳輸任務:程序不運行也可以傳輸,可以監視下載狀態,支持HTTP、HTTPS,但不支持FTP。
傳輸限制:上傳最大5MB,通過手機網絡下載最大20MB,通過WiFi最大100MB,這些數字可以通過修改TransferPreferences的值。每個程序最多可以請求25次。
后台傳輸命名空間:using Microsoft.Phone.BackgroundTransfer;
創建一個后台傳輸:POST用來發送文件到服務器。
Uri transferUri = new Uri(Uri.EscapeUriString(transferFileName), UriKind.RelativeOrAbsolute); // Create the new transfer request, passing in the URI of the file to // be transferred. transferRequest = new BackgroundTransferRequest(transferUri); // Set the transfer method. GET and POST are supported. transferRequest.Method = "GET";
設置傳輸目標:
string downloadFile = transferFileName.Substring(transferFileName.LastIndexOf("/") + 1); // Build the URI downloadUri = new Uri("shared/transfers/" + downloadFile, UriKind.RelativeOrAbsolute); transferRequest.DownloadLocation = downloadUri; // Set transfer options transferRequest.TransferPreferences = TransferPreferences.AllowCellularAndBattery;
開始傳輸:
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."); }
監視傳輸:TransferProcessChanged是為進度條准備的,TransferStatusChanged在完成或失敗時觸發。
// Bind event handlers to the progess and status changed events transferRequest.TransferProgressChanged += new EventHandler<BackgroundTransferEventArgs>( request_TransferProgressChanged); transferRequest.TransferStatusChanged += new EventHandler<BackgroundTransferEventArgs>( request_TransferStatusChanged);
void request_TransferProgressChanged(object sender, BackgroundTransferEventArgs e) { statusTextBlock.Text = e.Request.BytesReceived + " received."; }
void request_TransferStatusChanged(object sender, BackgroundTransferEventArgs e) { switch (e.Request.TransferStatus) { case TransferStatus.Completed: // If the status code of a completed transfer is 200 or 206, the // transfer was successful if (transferRequest.StatusCode == 200 ||transferRequest.StatusCode == 206) { // File has arrived OK – use it in the program }
移除一個傳輸:
try { BackgroundTransferService.Remove(transferRequest); } catch { }
聲音播放代理:聲音流可以存在獨立存儲內,機制與其他后台任務相同。