我正在开发一个UWP应用,该应用使用进程内后台任务来下载新的GitHub通知并将其显示为吐司通知。我正在使用MVVM灯。我使用 TimeTrigger 尝试了进程内后台任务,当应用程序处于前台或最小化时,一切都按预期工作。但是,当应用程序关闭时,后台任务将停止工作。监视任务管理器后,我发现后台任务已启动,但启动后立即关闭。因此,我使用了 ExtendedExecutionSession 来延长暂停时间。仍然没有用。使用“进程外”后台任务可以解决先前的问题,但会引入新的问题。由于无法调用API所需的应用数据(GitHub Auth数据),导致GitHub api调用在后台失败。
简而言之,我遇到以下问题:
我找到了以下解决方法:
我的问题是:
在处理任务中如何以及何时调用 ExtendedExecutionSession 。
如何编写进程间通信的代码,以便能够从后台应用程序访问应用程序数据
请注意,我已经在 MainPage.xaml.cs 中注册了后台任务。这是代码段:
var syncBuilder = Helpers.BackgroundTaskHelper.BuildBackgroundTask(
"SyncNotifications",
new TimeTrigger(15, false),
internetAvailableCondition,
userPresentCondition,
sessionConnectedCondition
);
syncBuilder.IsNetworkRequested = true;
syncBuilder.Register();
并且我覆盖了 App.xaml.cs 中的 OnBackgroundActivated 。这是代码spippet:
var deferral = args.TaskInstance.GetDeferral();
args.TaskInstance.Task.Completed += BackgroundTask_Completed;
var taskName = args.TaskInstance.Task.Name;
switch (taskName)
{
case "ToastNotificationBackgroundTask":
await CoreApplication
.MainView
.CoreWindow
.Dispatcher
.RunAsync(
CoreDispatcherPriority.Normal,
async () =>
{
var toastTriggerDetails = args.TaskInstance.TriggerDetails as ToastNotificationActionTriggerDetail;
var toastArgs = QueryString.Parse(toastTriggerDetails.Argument);
var notificationId = toastArgs["notificationId"];
if (!notificationId.IsNulloremptyOrNullorwhitespace())
{
await NotificationsService.MarkNotificationAsRead(notificationId);
}
});
break;
case "SyncNotifications":
await CoreApplication
.MainView
.CoreWindow
.Dispatcher
.RunAsync(
CoreDispatcherPriority.Normal,
async () =>
{
AppViewmodel.UnreadNotifications = await NotificationsService.GetAllNotificationsForCurrentUser(false, false);
await AppViewmodel.UnreadNotifications?.ShowToasts();
});
break;
}
答案 0 :(得分:0)
代码中的问题是您过早完成Deferral,即在异步调度程序工作项有机会执行之前。当应用程序位于前台时,此过程会起作用,因为该过程仍然会继续进行,但是在后台激活时,该过程将一直运行,直到您将延迟标记为完成,这意味着它将在您的任务代码有机会执行之前退出运行。
要了解我的意思,请尝试一些实验。在调试器下运行模仿您当前实现的代码,并观察中断点的执行顺序。这将帮助您意识到在实际代码运行之前,您正在调用Deferral.Complete:
protected async override void OnBgActivated()
{
await CoreApplication.MainView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
await PerformTaskAsync();
Debugger.Break();
});
Debugger.Break();
}
private async Task PerformTaskAsync()
{
await Task.Yield();
Debugger.Break();
return;
}
现在,您的解决方案很简单,在任务实际完成后,将Deferral.Complete()调用移至代码中的某个位置。您可能需要为此更改'deferral'的范围,并创建一个类级变量。