在使用計劃通知時,如果過於頻繁的做一些擷取或刪除Toast的操作,程式會拋出"無法找到元素"的異常。至於具體是什麼原因,暫時搞不清楚。異常提供的資訊實在有限。
不過Toast這些與UI互動並無多大關係資料,可以放到後台來處理,同時可以做一下訪問頻率的限制,從而減少拋出異常的幾率。
使用後台線程的一大特點是,互動過程變得流暢了,而底層的一些資料可以在非UI線程中處理。可以怎麼實現呢?本人是這麼考慮的,首先邏輯代碼放到Task.Run()中處理;同時維持一個是否正在處理Toast的標誌和一個請求處理toast的列表。當有新的處理請求到達而程式塊正在執行時,該請求就會被加入到請求列表中。當程式處理完一個請求之後,會從列表中尋找下一個請求並執行,如果列表為空白,該程式塊就會退出。
下面是代碼實現部分,其中Remove()函數使用了上面所說的機制。不過,此代碼有一個很大的缺點,就是非安全執行緒的(m_IsProcessing並沒有加鎖):
using System.Collections.Generic;using System.Threading.Tasks;using Windows.UI.Notifications;namespace Test.NotificationService{ public class ScheduledActionService { #region Data Members // 標誌是否正在處理請求 private static bool m_IsProcessing = false; // 維持toast的處理請求列表 private static List<string> m_ToastIds = new List<string>(); #endregion #region Constructor private ScheduledActionService() { } #endregion #region Public Methos /// <summary> /// 添加toast計劃通知 /// </summary> public static void Add(ScheduledToastNotification notification) { Task.Run(() => { ToastNotificationManager.CreateToastNotifier().AddToSchedule(notification); }); } /// <summary> /// 刪除toast計劃通知 /// </summary> /// /// <param name="notification">指定的toast通知</param> public static void Remove(ScheduledToastNotification notification) { ToastNotificationManager.CreateToastNotifier().RemoveFromSchedule(notification); } /// <summary> /// 刪除toast計劃通知 /// </summary> /// <param name="toastName">指定的toast通知的名字(id)</param> public static void Remove(string toastName) { Task.Run(() => { m_ToastIds.Add(toastName); if (m_IsProcessing) return; m_IsProcessing = true; ToastNotifier notifier = ToastNotificationManager.CreateToastNotifier(); while (m_ToastIds.Count > 0) { IReadOnlyList<ScheduledToastNotification> toasts = notifier.GetScheduledToastNotifications(); string toastId = m_ToastIds[0]; m_ToastIds.RemoveAt(0); if (toasts.Count > 0) { foreach (var toast in toasts) { if (toast.Id == toastId) notifier.RemoveFromSchedule(toast); } } } m_IsProcessing = false; } ); } /// <summary> /// 擷取系統已有的計劃通知數列表 /// </summary> public static IReadOnlyList<ScheduledToastNotification> GetScheduledToastNotifications() { return ToastNotificationManager.CreateToastNotifier().GetScheduledToastNotifications(); } public static IReadOnlyList<ScheduledToastNotification> Find(string toastName) { IReadOnlyList<ScheduledToastNotification> toasts = GetScheduledToastNotifications(); List<ScheduledToastNotification> qualifiedToasts = new List<ScheduledToastNotification>(); foreach (var item in toasts) { if (item.Id == toastName) qualifiedToasts.Add(item); } return qualifiedToasts; } #endregion }}
邏輯上應該有一些錯漏的地方,歡迎指正。