首页 文章

如何在UWP应用程序中使用后台任务

提问于
浏览
0

我'm developing a UWP app which uses in-process background task to download new GitHub notifications and show them as toast notifications. I' m使用MVVM灯 . 我使用TimeTrigger尝试了进程内后台任务,当应用程序处于前台或最小化时,一切都按预期工作 . 但是当应用关闭时,后台任务就会停止工作 . 在监视任务管理器之后,我发现后台任务启动但在启动后立即关闭 . 所以我使用 ExtendedExecutionSession 来延长暂停时间 . 它仍然没有用 . 使用Out of the process后台任务可以解决上一个问题,但会引入一个新问题 . 由于进行API调用所需的应用程序数据(GitHub Auth Data)不可访问,GitHub api调用在后台失败 .

简而言之,我有以下问题:

  • 在应用程序关闭时,进程后台任务不在后台运行

  • 当我使用Octokit对GitHub进行API调用时,后台任务可以共享应用程序数据(例如我的GitHub Auth数据)

我发现了这些变通方法:

  • ExtendedExecutionSession 与进程内后台任务一起使用

  • 在进程后台任务之外使用 Inter process communication

我的问题是:

  • 如何以及何时在进程内任务中调用 ExtendedExecutionSession .

  • 如何编码 Inter-process communication 以便能够从后台应用程序访问应用程序数据

请注意,我已在 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 . 这是代码片段:

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;
 }

1 回答

  • 0

    您的代码中的问题是您过早地完成了延迟,即在您的异步调度程序工作项有机会执行之前 . 当应用程序处于前台时,这种情况就会发生,因为无论如何都会保留该进程,但是当在后台激活时,该进程将一直运行,直到您将延迟标记为完成,这意味着它将在您的任务代码有机会之前退出跑 .

    要了解我的意思,请尝试一下小实验 . 运行此代码,模拟调试器下的当前实现,并观察断点被命中的顺序 . 这将帮助您在实际代码运行之前意识到您正在调用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()调用移动到代码中的某个位置 . 您可能必须为此更改“延迟”的范围并创建类级变量 .

相关问题