Как работать с фоновыми задачами в приложениях UWP - PullRequest
0 голосов
/ 05 октября 2018

Я разрабатываю приложение UWP, которое использует фоновую задачу в процессе для загрузки новых уведомлений GitHub и отображения их в качестве всплывающих уведомлений.Я использую MVVM light.Я пытался выполнить фоновые задачи в процессе с TimeTrigger , все работает, как ожидалось, когда приложение находится на переднем плане или свернуто.Но когда приложение закрыто, фоновые задачи перестают работать.После мониторинга диспетчера задач я обнаружил, что фоновая задача запускается, но сразу после запуска закрывается.Поэтому я использовал ExtendedExecutionSession , чтобы продлить приостановку.Тем не менее это не работает.Использование Вне процесса фоновые задачи решают предыдущую проблему, но вводят новую проблему.Вызов API GitHub завершился неудачно в фоновом режиме из-за недоступности данных приложения (GitHub Auth Data), которые требуются для вызова API.

Короче говоря, у меня есть следующие проблемы:

  1. Фоновые задачи процесса не запускаются в фоновом режиме при закрытии приложения.
  2. Вне процесса фоновые задачи могут совместно использовать данные приложения (например, данные GitHub Auth в моем случае), когда я выполняю вызов API дляGitHub с использованием Octokit

Я нашел следующие обходные пути:

  1. Использование ExtendedExecutionSession с фоновыми задачами в процессе
  2. Использование Межпроцессное взаимодействие с фоновыми задачами вне процесса

Мои вопросы:

  1. Как и когда мне следует позвонить ExtendedExecutionSession в внутрипроцессных задачах.

  2. Как кодировать Межпроцессное взаимодействие , чтобы иметь возможность доступа к данным приложения из фонового приложения

Обратите внимание, что я зарегистрировал фоновые задачи в MainPage.xaml.cs .Вот фрагмент кода:

var syncBuilder = Helpers.BackgroundTaskHelper.BuildBackgroundTask(
                        "SyncNotifications",
                        new TimeTrigger(15, false),
                        internetAvailableCondition,
                        userPresentCondition,
                        sessionConnectedCondition
                   );
syncBuilder.IsNetworkRequested = true;            
syncBuilder.Register();

И я переопределил OnBackgroundActivation в App.xaml.cs .Вот кодовая отметка:

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 голосов
/ 07 октября 2018

Проблема в вашем коде заключается в том, что вы слишком рано завершаете отсрочку, т. Е. До того, как рабочие элементы асинхронного диспетчера успели выполнить.Это работает, когда приложение находится на переднем плане, потому что процесс все равно останется без изменений, но при активации в фоновом режиме процесс будет выполняться только до тех пор, пока вы не отметите отсрочку как завершенную, что означает, что он завершится до того, как ваш код задачи сможетзапустить.

Чтобы понять, что я имею в виду, попробуйте небольшой эксперимент.Запустите этот код, который имитирует вашу текущую реализацию, в отладчике и посмотрите, в каком порядке были достигнуты точки останова.Это поможет вам понять, что вы вызываете 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' и создать переменную уровня класса.

...