#c# #uwp #prism #background-task #prism-6
#c# #uwp #призма #фоновая задача #prism-6
Вопрос:
Последние несколько дней я бился головой о монитор. Я разрабатываю приложение UWP для Windows Store (нацеленное на 14393) и использую фреймворки Prism / Unity для MVVM / IoC.
Поскольку данные, необходимые для обновления живой плитки, хранятся в классе, реализующем шаблон репозитория, и все управляется через Unity, я не создаю отдельный процесс для фонового выполнения, поэтому даже упрощаю весь процесс регистрации BGTask.
Фактический регистрационный код BGTask выглядит следующим образом:
var servicingTaskAlreadyRegistered = false;
var tileUpdaterTaskAlreadyRegistered = false;
foreach (var t in BackgroundTaskRegistration.AllTasks)
{
if (t.Value.Name == Constants.BgTileUpdaterTaskName)
tileUpdaterTaskAlreadyRegistered = true;
else if (t.Value.Name.Equals(Constants.BgServicingTaskName))
servicingTaskAlreadyRegistered = true;
}
var reqAccess = await BackgroundExecutionManager.RequestAccessAsync();
if (reqAccess == BackgroundAccessStatus.Denied ||
reqAccess == BackgroundAccessStatus.DeniedBySystemPolicy ||
reqAccess == BackgroundAccessStatus.DeniedByUser ||
reqAccess == BackgroundAccessStatus.Unspecified)
return false;
if (!servicingTaskAlreadyRegistered)
{
var servicingTaskBuilder = new BackgroundTaskBuilder();
servicingTaskBuilder.Name = Constants.BgServicingTaskName;
servicingTaskBuilder.SetTrigger(new SystemTrigger(SystemTriggerType.ServicingComplete, false));
servicingTaskBuilder.Register();
}
if (tileUpdaterTaskAlreadyRegistered)
return true;
var builder = new BackgroundTaskBuilder();
builder.Name = Constants.BgTileUpdaterTaskName;
builder.SetTrigger(new TimeTrigger(TileUpdateFrequencyMinutes, false));
//builder.SetTrigger(new MaintenanceTrigger(TileUpdateFrequencyMinutes, false));
builder.IsNetworkRequested = true;
builder.Register();
Регистрация успешно завершена. Выполнение Get-AppBackgroundTask в PowerShell показывает обе задачи, как и должно быть. Однако TimeTrigger никогда не запускается. Замена TimeTrigger на MaintenanceTrigger устраняет проблему, хотя смартфон необходимо подключить к зарядному устройству, что не является приемлемым решением.
Принудительное выполнение задачи через VisualStudio или PowerShell (Start-AppBackgroundTask -TaskId ) выполняется правильно, и плитка обновляется.
У вас есть еще какой-нибудь полезный совет, которым можно поделиться?
Редактировать 01.12.2017 Я создал репозиторий, содержащий решение Visual Studio с двумя проектами:
- Простой тест живой плитки: как можно проще обновлять живую плитку каждые 15 минут с помощью UWP. Все работает так, как ожидалось.
- Призма для тестирования живой плитки: опять же, простое преобразование вышеупомянутого проекта с использованием Prism и Unity. Не работает, потому что, когда ОС пытается запустить приложение для обновления плитки, контейнер Unity имеет значение null (не инициализируется).
Это объясняет, почему у меня возникла проблема: Unity не инициализируется, я не могу получить данные через репозитории, приложение вылетает и GG.
Теперь мне просто нужно понять, почему Unity недоступен в методе OnBackgroundActivated. Почти все, ребята!!
Воспроизведение: https://github.com/eraser85/LiveTileTestRepro
Ответ №1:
Для меня код выглядит нормально, единственное, что я бы попытался изменить здесь, это использование IsNetwokRequested
свойства и значения TimeTrigger
частоты, вы уверены, что используемая вами константа / переменная больше или равна 15?
Вот пример:
BackgroundTaskBuilder builder = new BackgroundTaskBuilder { Name = "YourBgTaskName" };
builder.SetTrigger(new TimeTrigger(15, false));
builder.AddCondition(new SystemCondition(SystemConditionType.InternetAvailable));
builder.Register();
Комментарии:
1. Что касается этой переменной, это просто
private const int TileUpdateFrequencyMinutes = 15;
. Я поместил его за переменной на случай, если захочу выставить это значение на странице настроек. Но да, я уверен, что это 15 минут (я только что проверил, следуя вашему совету! :)). Что касается требуемого IsNetworkRequired, в последующие месяцы после моего поста я прочитал в Интернете те же проблемы, о которых вы упоминаете, и уже давно обновил код, и он в основном такой же, как тот, который вы предлагаете. К сожалению, у меня все еще возникают проблемы. В любом случае спасибо!2. @MicheleM Вы пробовали создать новое решение с другим проектом UWP, который содержит пустое приложение, которое настраивает и запускает фоновую задачу с одним процессом, чтобы проверить, работает ли она там? Таким образом, вы, по крайней мере, сможете понять, что-то не так с вашим проектом приложения, в частности, или с вашей установкой VS, или с системными настройками, или с чем-то еще. Я имею в виду, что ваш код с упомянутыми вами дополнительными изменениями выглядит на 100% правильным для меня.
3. Нет, пока нет. Я полагаю, что на данный момент это единственный способ. Я собираюсь создать два новых проекта: стандартный пустой проект с минимальным обновлением живой плитки и еще один, в который встроена prism: я подозреваю, что проблема, с которой я столкнулся, каким-то образом связана с этим. Спасибо, я обновлю этот пост, как только у меня что-нибудь появится.
4. Я обновил исходное сообщение дополнительной информацией! Создание репро оказалось действительно очень полезным для сужения возможностей, и, похоже, я начинаю видеть свет в конце туннеля 🙂
Ответ №2:
Итак, после еще нескольких тестов я, наконец, нашел решение.
Как уже упоминалось, проблема возникла из-за Prism: в основном, при запуске ОС и входе через OnBackgroundActivated()
контейнер IoC не инициализировался.
Решение, даже если оно кажется хакерским, на самом деле вполне жизнеспособно и правильно (ИМХО!). В вашем OnBackgroundActivated()
случае просто инициализируйте все, как будто начинаете с нуля (посмотрите на источник Prism для деталей реализации): в моем конкретном случае я просто вызвал CreateAndConfigureContainer()
и перерегистрировал все, что я ввел OnInitializeAsync()
(например, репозитории, сервисы ..).
Я открыл проблему с разработчиками. Возможно, решение уже в пути, но в то же время это должно сработать.