重新想象 Windows 8.1 Store Apps (91) - 后台任務的新特性: 下載和上傳的新特性, 程序啟動前預下載網絡資源, 后台任務的其它新特性
作者:webabcd
介紹
重新想象 Windows 8.1 Store Apps 之后台任務的新特性
- 下載和上傳的新特性
- 程序啟動前預下載網絡資源
- 后台任務的其它新特性
示例
1、本例用於說明 win8.1 中后台下載和上傳的新特性(本例用后台下載說明,后台上傳與此類似)
TransferNew.xaml
<Page x:Class="Windows81.BackgroundTask.TransferNew" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Windows81.BackgroundTask" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="Transparent"> <StackPanel Margin="120 0 0 0"> <ScrollViewer Height="100"> <TextBlock Name="lblMsg" FontSize="14.667" TextWrapping="Wrap" /> </ScrollViewer> <Button Name="btnDownload" Content="后台下載文件" Margin="0 10 0 0" Click="btnDownload_Click" /> </StackPanel> </Grid> </Page>
TransferNew.xaml.cs
/* * 本例用於說明 win8.1 中后台下載和上傳的新特性(本例用后台下載說明,后台上傳與此類似) * 以下僅列出新增的功能,關於上傳和下載的基礎請參見:http://www.cnblogs.com/webabcd/archive/2013/10/21/3379890.html * * * BackgroundTransferGroup - 用於分組傳輸任務,可以指定此分組中的傳輸任務是並行的還是串行的 * static CreateGroup(string name) - 創建一個指定名字的傳輸分組,此名字需要是全系統唯一的,建議用 guid * Name - 傳輸分組的名字 * TransferBehavior - 傳輸行為(BackgroundTransferBehavior 枚舉:Parallel 或 Serialized) * * BackgroundDownloader - 后台下載任務管理器 * static GetCurrentDownloadsForTransferGroupAsync(BackgroundTransferGroup group) - 獲取指定傳輸分組下的所有下載任務(BackgroundTransferGroup 是 win8.1 新增的概念,但是仍然保留了原來 win8 里的 Group 的概念) * TransferGroup - 指定此下載任務管理器的 BackgroundTransferGroup * SuccessToastNotification - 此下載任務管理器中的所有傳輸任務均成功之后調用的 toast 通知 * FailureToastNotification - 有傳輸任務失敗后調用的 toast 通知 * SuccessTileNotification - 此下載任務管理器中的所有傳輸任務均成功之后調用的 tile 通知 * FailureTileNotification - 有傳輸任務失敗后調用的 tile 通知 * static RequestUnconstrainedDownloadsAsync(IEnumerable<DownloadOperation> operations) - 告訴系統,希望指定的下載任務是無約束的(返回一個 UnconstrainedTransferRequestResult 對象) * * UnconstrainedTransferRequestResult - 向系統請求無約束下載時,系統返回的結果 * IsUnconstrained - 系統是否允許你指定的下載任務是無約束的(所謂無約束就是不存在當設備依靠電池運行時通常與后台網絡操作相關聯的資源限制) * * DownloadOperation - 下載任務對象 * Priority - 下載任務的優先級(BackgroundTransferPriority 枚舉:Default 或 High) */ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Windows.Data.Xml.Dom; using Windows.Networking.BackgroundTransfer; using Windows.Storage; using Windows.UI.Notifications; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.Web; namespace Windows81.BackgroundTask { public sealed partial class TransferNew : Page { private BackgroundTransferGroup _transferGroup; public TransferNew() { this.InitializeComponent(); } // 后台下載一個文件 private async void btnDownload_Click(object sender, RoutedEventArgs e) { // 下載地址(注意需要在 Package.appxmanifest 中增加對 .rar 類型文件的關聯) Uri sourceUri = new Uri("http://files.cnblogs.com/webabcd/Windows8.rar", UriKind.Absolute); StorageFile destinationFile; try { // 保存的目標地址 destinationFile = await KnownFolders.DocumentsLibrary.CreateFileAsync("Windows8.rar", CreationCollisionOption.GenerateUniqueName); } catch (Exception ex) { lblMsg.Text += ex.ToString(); lblMsg.Text += Environment.NewLine; return; } // 創建一個后台下載任務管理器 BackgroundDownloader backgroundDownloader = new BackgroundDownloader(); // 創建一個傳輸分組,並指定此分組中的傳輸任務是並行的還是串行的 _transferGroup = BackgroundTransferGroup.CreateGroup("webabcdBackground"); _transferGroup.TransferBehavior = BackgroundTransferBehavior.Parallel; backgroundDownloader.TransferGroup = _transferGroup; // 設置 SuccessToastNotification XmlDocument successToastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText01); successToastXml.GetElementsByTagName("text").Item(0).InnerText = "所有任務全部執行成功"; ToastNotification successToast = new ToastNotification(successToastXml); backgroundDownloader.SuccessToastNotification = successToast; // 設置 FailureToastNotification XmlDocument failureToastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText01); failureToastXml.GetElementsByTagName("text").Item(0).InnerText = "至少有一個下載任務失敗了"; ToastNotification failureToast = new ToastNotification(failureToastXml); backgroundDownloader.FailureToastNotification = failureToast; // 設置 SuccessTileNotification XmlDocument successTileXml = TileUpdateManager.GetTemplateContent(TileTemplateType.TileSquare150x150Text03); XmlNodeList successTextNodes = successTileXml.GetElementsByTagName("text"); successTextNodes.Item(0).InnerText = "所有"; successTextNodes.Item(1).InnerText = "任務"; successTextNodes.Item(2).InnerText = "全部"; successTextNodes.Item(3).InnerText = "成功"; TileNotification successTile = new TileNotification(successTileXml); successTile.ExpirationTime = DateTime.Now.AddMinutes(10); backgroundDownloader.SuccessTileNotification = successTile; // 設置 FailureTileNotification XmlDocument failureTileXml = TileUpdateManager.GetTemplateContent(TileTemplateType.TileSquare150x150Text03); XmlNodeList failureTextNodes = failureTileXml.GetElementsByTagName("text"); failureTextNodes.Item(0).InnerText = "至少"; failureTextNodes.Item(1).InnerText = "一個"; failureTextNodes.Item(2).InnerText = "任務"; failureTextNodes.Item(3).InnerText = "失敗"; TileNotification failureTile = new TileNotification(failureTileXml); failureTile.ExpirationTime = DateTime.Now.AddMinutes(10); backgroundDownloader.FailureTileNotification = failureTile; // 創建一個下載任務,並指定其優先級 DownloadOperation download = backgroundDownloader.CreateDownload(sourceUri, destinationFile); download.Priority = BackgroundTransferPriority.High; // 向系統請求,將指定的下載任務設置為無約束下載 List<DownloadOperation> requestOperations = new List<DownloadOperation>(); requestOperations.Add(download); UnconstrainedTransferRequestResult result = await BackgroundDownloader.RequestUnconstrainedDownloadsAsync(requestOperations); // 監視指定的后台下載任務 await HandleDownloadAsync(download); } /// <summary> /// 監視指定的后台下載任務 /// </summary> /// <param name="download">后台下載任務</param> private async Task HandleDownloadAsync(DownloadOperation download) { try { lblMsg.Text = "start"; // 當下載進度發生變化時的回調函數 Progress<DownloadOperation> progressCallback = new Progress<DownloadOperation>(DownloadProgress); // 所有下載任務的關聯的 CancellationTokenSource 對象(這個最好摘出來,因為不用的時候最好手工 Dispose 掉) CancellationTokenSource _cancelToken = new CancellationTokenSource(); await download.StartAsync().AsTask(_cancelToken.Token, progressCallback); // 新增一個后台下載任務 // 下載完成后獲取服務端的響應信息 ResponseInformation response = download.GetResponseInformation(); lblMsg.Text += "Completed: " + response.ActualUri + "-" + response.StatusCode.ToString(); lblMsg.Text += Environment.NewLine; } catch (TaskCanceledException) // 調用 CancellationTokenSource.Cancel() 后會拋出此異常 { lblMsg.Text += "Canceled: " + download.Guid; lblMsg.Text += Environment.NewLine; } catch (Exception ex) { // 將異常轉換為 WebErrorStatus 枚舉,如果獲取到的是 WebErrorStatus.Unknown 則說明此次異常不是涉及 web 的異常 WebErrorStatus error = BackgroundTransferError.GetStatus(ex.HResult); lblMsg.Text += ex.ToString(); lblMsg.Text += Environment.NewLine; } finally { } } // 進度發生變化時,顯示最新的進度信息 private void DownloadProgress(DownloadOperation download) { lblMsg.Text = download.Progress.BytesReceived.ToString("#,0") + " / " + download.Progress.TotalBytesToReceive.ToString("#,0"); } } }
2、演示如何對指定 web 資源預下載(系統會嘗試在用戶啟動 app 之前下載指定的資源,也就是說不管 app 是否打開,系統都會在其覺得合適的時候對指定的資源做預下載)
ContentPrefetcher.xaml
<Page x:Class="Windows81.BackgroundTask.ContentPrefetcher" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Windows81.BackgroundTask" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="Transparent"> <StackPanel Margin="120 0 0 0"> <TextBlock Name="lblMsg" FontSize="14.667" TextWrapping="Wrap" /> <Button Name="btnAddContentPrefetcher" Content="添加一個“預下載”任務" Click="btnAddContentPrefetcher_Click" Margin="0 10 0 0" /> <StackPanel Name="pnlStatus" Margin="0 10 0 0" /> </StackPanel> </Grid> </Page>
ContentPrefetcher.xaml.cs
/* * ContentPrefetcher - 對指定 web 資源預下載(系統會嘗試在用戶啟動 app 之前下載指定的資源,也就是說不管 app 是否打開,系統都會在其覺得合適的時候對指定的資源做預下載) * ContentUris - 需要加入到“預下載”的 uri * IndirectContentUri - 指定一個遠程 xml 地址,此 xml 用於描述需要“預下載”的資源列表,格式如下 * <?xml version="1.0" encoding="utf-8"?> * <prefetchUris> * <uri>http://www.w1.com</uri> * <uri>http://www.w2.com</uri> * <uri>http://www.w3.com</uri> * </prefetchUris> * LastSuccessfulPrefetchTime - 最近一次成功地預下載的時間 */ using System; using System.Threading.Tasks; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; namespace Windows81.BackgroundTask { public sealed partial class ContentPrefetcher : Page { public ContentPrefetcher() { this.InitializeComponent(); UpdateStatus(); } private void btnAddContentPrefetcher_Click(object sender, RoutedEventArgs e) { // 向預下載中心增加一個預下載任務 Windows.Networking.BackgroundTransfer.ContentPrefetcher.ContentUris.Add(new Uri("http://www.baidu.com")); // 清空預下載任務 // Windows.Networking.BackgroundTransfer.ContentPrefetcher.ContentUris.Clear(); // 更新狀態 UpdateStatus(); } private async void UpdateStatus() { pnlStatus.Children.Clear(); foreach (Uri uri in Windows.Networking.BackgroundTransfer.ContentPrefetcher.ContentUris) { string url = uri.ToString(); bool cached = await CheckStatus(uri); pnlStatus.Children.Add(new TextBlock() { Text = url + " - " + cached.ToString() }); } DateTimeOffset? lastPrefetchTime = Windows.Networking.BackgroundTransfer.ContentPrefetcher.LastSuccessfulPrefetchTime; if (lastPrefetchTime != null) { lblMsg.Text = "最近一次成功地“預下載”了內容的時間是:" + lastPrefetchTime.Value.ToString("yyyy-MM-dd hh:mm:ss"); } else { lblMsg.Text = "還沒有“預下載”成功過"; } } private async Task<bool> CheckStatus(Uri uri) { // 只從本地緩存加載指定的 http 資源 var filter = new Windows.Web.Http.Filters.HttpBaseProtocolFilter(); filter.CacheControl.ReadBehavior = Windows.Web.Http.Filters.HttpCacheReadBehavior.OnlyFromCache; var httpClient = new Windows.Web.Http.HttpClient(filter); var request = new Windows.Web.Http.HttpRequestMessage(Windows.Web.Http.HttpMethod.Get, uri); try { // 指定的資源在本地有緩存 await httpClient.SendRequestAsync(request); return true; } catch { // 指定的資源在本地無緩存 return false; } } } }
3、演示后台任務的其它新特性
Other.xaml
<Page x:Class="Windows81.BackgroundTask.Other" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Windows81.BackgroundTask" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="Transparent"> <StackPanel Margin="120 0 0 0"> <TextBlock Name="lblMsg" FontSize="14.667" Margin="0 10 0 0" Text="詳見 .cs 中的代碼注釋" /> </StackPanel> </Grid> </Page>
Other.xaml.cs
/* * win 8.1 中與后台任務相關的其它新特性: * 1、在“設置”->“搜索和應用”->“通知”->“免打擾時間”中可以設置免打擾時間 * 2、免打擾時間內,所有后台任務均暫停,免打擾時間過后,后台任務將隨機在不同時間點啟動 * 3、免打擾時間允許兩種例外:來電和鬧鍾 * 4、后台任務 IBackgroundTaskInstance.Canceled 如果 5 秒內沒有完成,則系統會終止該應用,並生成錯誤報告上傳至 windows 商店的開發人員賬戶 * 5、Windows.ApplicationModel.Background.BackgroundWorkCost.CurrentBackgroundWorkCost 當前后台任務的開銷(BackgroundWorkCostValue 枚舉:Low, Medium, High) * 6、IBackgroundTaskInstance.SuspendedCount - 由資源管理政策導致后台任務掛起的次數(win8 就支持,之前忘了寫了) * * * 關於后台任務的基礎請參見:http://www.cnblogs.com/webabcd/archive/2013/10/15/3369581.html */ using Windows.ApplicationModel.Background; using Windows.UI.Xaml.Controls; namespace Windows81.BackgroundTask { public sealed partial class Other : Page { public Other() { this.InitializeComponent(); } } }
OK
[源碼下載]
