在使用计划通知时,如果过于频繁的做一些获取或删除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
}
}
逻辑上应该有一些错漏的地方,欢迎指正。