動態磁貼(Live Tile)是WP系統的大亮點之一,一直以來受到廣大用戶的喜好。這一講主要研究如何在UWP應用裏經過後臺任務添加和使用動態磁貼功能。服務器
從WP7到Win8,再到Win10 UWP,磁貼模板不斷進行調整和優化,目前磁貼模板已經發展到第三代,通常稱之爲「Adaptive Tile Templates」。網絡
在運用UWP動態磁貼以前,請先了解一下自適應磁貼的語法規則。關於自適應磁貼模板的語法規則,請詳讀這篇文章:http://blogs.msdn.com/b/tiles_and_toasts/archive/2015/06/30/adaptive-tile-templates-schema-and-documentation.aspxapp
磁貼的「動態」,在於它能不斷地進行更新,展現新的內容。磁貼又可分爲主磁貼(即由應用列表Pin到桌面的磁貼)和二級磁貼(即由應用內部經過程序控制Pin到桌面的磁貼)。這兩種磁貼都支持小、中、寬和大磁貼4種尺寸。異步
Windows.UI.Notifications.TileUpdater能夠用來管理和修改當前磁貼的內容,從而達到更新磁貼的目的。TileUpdater對象必須經過Windows.UI.Notifications.TileUpdateManager的CreateTileUpdaterForApplication或CreateTileUpdaterForSecondaryTile 方法來獲取。如:async
1 var updater = TileUpdateManager.CreateTileUpdaterForApplication();
1 var updater = TileUpdateManager.CreateTileUpdaterForSecondaryTile("appdota2");
而後調用updater的Update方法便可實現對內容的更新。Update方法須要傳入一個TileNotification對象:ide
1 // 2 // 摘要: 3 // 將內容或外觀的更改應用於圖塊。 4 // 5 // 參數: 6 // notification: 7 // 爲平鋪的內容提供新的 XML 定義的對象。 8 public void Update(TileNotification notification);
顧名思義,TileNotifiction承載着要進行通知的磁貼模板,磁貼模板實際上就是一個定義好的XML文件。在UWP裏,這個磁貼模板就須要按照「Adaptive Tile Templates」的規則來定義。優化
磁貼更新的方式能夠經過程序內部控制,如在後臺請求新數據並進行更新,這種方式也就是經過後臺任務(Background Task)來實現更新;也能夠經過推送通知使磁貼產生變化。咱們今天重點講後臺任務的更新磁貼方法。ui
後臺任務更新邏輯:編碼
1.應用首先註冊一個後臺任務spa
2.後臺任務按期向服務器請求新數據
3.服務器傳回新的數據
4.後臺任務經過TileUpdater更新磁貼內容
建立一個WinRT組件,再建立一個類叫LiveTileTask,而且實現IBackgroundTask接口,必須實現接口的Run方法:
1 public sealed class LiveTileTask : IBackgroundTask 2 { 3 public async void Run(IBackgroundTaskInstance taskInstance) 4 { 5 var deferral = taskInstance.GetDeferral(); 6 // TODO: 獲取數據,更新磁貼邏輯 8 deferral.Complete(); 10 } 11 }
Run方法中必須獲取deferral對象,而且執行完成後須要調用deferral對象關閉,由於咱們在後臺任務中是須要執行異步代碼的,因此獲取完deferral對象以後,大約有5秒鐘的時間能夠進行異步操做,超過期間系統就會強制釋放deferral對象。這樣能保證較好的用戶體驗,若是異步請求的時間過長,天然會認爲執行失敗而不會去更新磁貼了。
接下來再Run方法中間位置開始執行請求數據的任務:
1 public async void Run(IBackgroundTaskInstance taskInstance) 2 { 3 var deferral = taskInstance.GetDeferral(); 4 5 await GetLatestNews(); 6 7 deferral.Complete(); 8 } 9 10 private IAsyncOperation<string> GetLatestNews() 11 { 12 try 13 { 14 return AsyncInfo.Run(token => GetNews()); 15 } 16 catch (Exception) 17 { 18 // ignored 19 } 20 return null; 21 }
其中GetNews方法即向服務端請求數據,完成後能夠開始更新磁貼:
1 private async Task<string> GetNews() 2 { 3 try 4 { 5 var response = await ApiService.GetHotNewsListAsync(); 6 if (response?.Data != null) 7 { 8 var news = response.Data.Take(5).ToList(); 9 UpdatePrimaryTile(news); 10 UpdateSecondaryTile(news); 11 } 12 13 } 14 catch (Exception) 15 { 16 // ignored 17 } 18 return null; 19 }
注意磁貼最多隻能更新5個,因此只處理返回數據的前5個。
更新磁貼的方法很是簡單:
1 private void UpdatePrimaryTile(List<News> news) 2 { 3 if (news == null || !news.Any()) 4 { 5 return; 6 } 7 8 try 9 { 10 var updater = TileUpdateManager.CreateTileUpdaterForApplication(); 11 updater.EnableNotificationQueueForWide310x150(true); 12 updater.EnableNotificationQueueForSquare150x150(true); 13 updater.EnableNotificationQueueForSquare310x310(true); 14 updater.EnableNotificationQueue(true); 15 updater.Clear(); 16 17 foreach (var n in news) 18 { 19 var doc = new XmlDocument(); 20 var xml = string.Format(TileTemplateXml, n.Pic, n.Title, n.Desc); 21 doc.LoadXml(WebUtility.HtmlDecode(xml), new XmlLoadSettings 22 { 23 ProhibitDtd = false, 24 ValidateOnParse = false, 25 ElementContentWhiteSpace = false, 26 ResolveExternals = false 27 }); 28 29 updater.Update(new TileNotification(doc)); 30 } 31 } 32 catch (Exception) 33 { 34 // ignored 35 } 36 }
咱們採用隊列的形式容許磁貼逐個更新,還有一個須要注意的地方,服務端返回的數據可能帶有轉義字符,在加載模板XML的時候必須作一下編碼處理,不然可能致使異常而沒法更新磁貼。固然其中的TileTemplateXml本身根據自適應磁貼的規則定義便可,舉例:
1 private const string TileTemplateXml = @" 2 <tile branding='name'> 3 <visual version='3'> 4 <binding template='TileMedium'> 5 <image src='{0}' placement='peek'/> 6 <text>{1}</text> 7 <text hint-style='captionsubtle' hint-wrap='true'>{2}</text> 8 </binding> 9 <binding template='TileWide'> 10 <image src='{0}' placement='peek'/> 11 <text>{1}</text> 12 <text hint-style='captionsubtle' hint-wrap='true'>{2}</text> 13 </binding> 14 <binding template='TileLarge'> 15 <image src='{0}' placement='peek'/> 16 <text>{1}</text> 17 <text hint-style='captionsubtle' hint-wrap='true'>{2}</text> 18 </binding> 19 </visual> 20 </tile>";
這個模板實現的效果是如同商店應用的Peek動態更新效果:
Animated | Peek shown | Peek sliding up | Content shown | Peek sliding down |
---|---|---|---|---|
注意後臺任務必須在前臺程序進行觸發(Trigger)設置,即所謂的註冊後臺任務。後臺任務將根據觸發器是否被觸發而執行。
Win8.1的Trigger有SystemTrigger, TimeTrigger, MaintenaceTrigger, DeviceUseTrigger, DeviceServingTrigger, PushNotificationTrigger;
WP8.1的Trigger有CachedFileUpdaterTrigger, DeviceConnectionChangedTrigger, GattCharacteristicNotificationTrigger, RfcommonConnectionTrigger, LocationTrigger;
Win10新增了以下Trigger:AppointmentStoreNotificationTrigger, ContactStoreNotificationTrigger, BluetoothLEAdvertisementWarcherTrigger, BluetoothLEAdvertisementPublisherTrigger, DeviceWatcherTrigger, ActivitySensorTrigger, SensorDataThresholdTrigger, ToastNotificationHistoryChangedTrigger, ToastNotificationActionTrigger, ApplicationTrigger, SocketActivityTrigger。
若是咱們要進行週期性的磁貼更新,那麼咱們能夠將用Timer觸發器去進行觸發,須要在Package.appxmanifest中聲明一個後臺任務,支持的任務類型勾選計時器,且應用設置中Entry Point設置爲LiveTileTask的完整類名。
在前臺程序的App.cs或其餘地方進行設置:
1 private const string LIVETILETASK = "LIVETILETAKS"; 2 private async void RegisterLiveTileTask() 3 { 4 var status = await BackgroundExecutionManager.RequestAccessAsync(); 5 if (status == BackgroundAccessStatus.Unspecified || status == BackgroundAccessStatus.Denied) 6 { 7 return; 8 } 9 BackgroundTaskRegistration.AllTasks.ForEach(t => 10 { 11 if (t.Value.Name == LIVETILETASK) 12 { 13 t.Value.Unregister(true); 14 } 15 }); 16 17 var taskBuilder = new BackgroundTaskBuilder 18 { 19 Name = LIVETILETASK, 20 TaskEntryPoint = typeof(LiveTileTask).FullName 21 }; 22 taskBuilder.AddCondition(new SystemCondition(SystemConditionType.InternetAvailable)); 23 24 var updater = TileUpdateManager.CreateTileUpdaterForApplication(); 25 updater.Clear(); 26 var updater2 = TileUpdateManager.CreateTileUpdaterForSecondaryTile("appdota2"); 27 updater2.Clear();33 34 taskBuilder.SetTrigger(new TimeTrigger(60, false)); 35 taskBuilder.Register(); 36 }
對於後臺任務,還能夠設定必定的條件使其觸發,如當沒有網絡的狀況下,即便到了時間週期,也不會去觸發後臺任務。
這樣就實行了每一個60分鐘觸發一次後臺任務,讓後臺任務去請求新的數據,並將磁貼已隊列的形式循環進行更新。