Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Uwaga / Notatka
W tym artykule opisano zadania w tle utworzone za pomocą interfejsu API środowisko wykonawcze systemu Windows (WinRT) BackgroundTaskBuilder w przestrzeni nazw Windows.ApplicationModel.Background dla aplikacji z tożsamością pakietu, w tym aplikacji UWP i aplikacji klasycznych w pakiecie. Jeśli tworzysz nową aplikację lub migrujesz istniejącą aplikację do Zestaw SDK do aplikacji systemu Windows, zobacz Używanie zadań w tle w aplikacjach Windows i Strategia migracji zadań w tle.
Dowiedz się, jak utworzyć i zarejestrować zadanie w tle w aplikacji za pomocą klasy środowisko wykonawcze systemu Windows (WinRT) BackgroundTaskBuilder.
Zarejestruj zadanie w tle
Zobacz przykład BackgroundTask aby zapoznać się z kompletnym przykładem rejestrowania zadania w tle w aplikacji Universal Windows Platform (UWP).
W poniższym przykładzie pokazano rejestrację zadania Win32 COM uruchamianego na cyklicznym 15-minutowym czasomierzu.
Aby zarejestrować zadanie w tle, należy najpierw utworzyć nowe wystąpienie klasy BackgroundTaskBuilder . Klasa BackgroundTaskBuilder służy do tworzenia i rejestrowania zadań w tle w aplikacji. W poniższym przykładzie kodu pokazano, jak utworzyć nowe wystąpienie BackgroundTaskBuilder klasy:
using System;
using Windows.ApplicationModel.Background;
public IBackgroundTaskRegistration RegisterBackgroundTaskWithSystem(IBackgroundTrigger trigger, Guid entryPointClsid, string taskName)
{
BackgroundTaskBuilder builder = new BackgroundTaskBuilder();
builder.SetTrigger(trigger);
builder.SetTaskEntryPointClsid(entryPointClsid);
BackgroundTaskRegistration registration;
if (builder.Validate())
{
registration = builder.Register(taskName);
}
else
{
registration = null;
}
return registration;
}
RegisterBackgroundTaskWithSystem(new TimeTrigger(15, false), typeof(TimeTriggeredTask).GUID, typeof(TimeTriggeredTask).Name);
Metoda RegisterBackgroundTaskWithSystem przyjmuje trzy parametry:
-
trigger: wyzwalacz, który uruchomi zadanie w tle. -
entryPointClsid: identyfikator klasy punktu wejścia zadania w tle. -
taskName: nazwa zadania w tle.
Metoda RegisterBackgroundTaskWithSystem tworzy nowe wystąpienie BackgroundTaskBuilder klasy i ustawia identyfikator klasy wyzwalacza i punktu wejścia dla zadania w tle. Następnie metoda rejestruje zadanie w tle w systemie.
Uwaga / Notatka
Ta klasa nie jest zwinna, co oznacza, że należy wziąć pod uwagę jej model wątkowy i zachowanie marshalingu. Aby uzyskać więcej informacji, zobacz Threading and Marshaling (C++/CX) i Za pomocą obiektów środowisko wykonawcze systemu Windows w środowisku wielowątkowym (.NET).
Obsługa trybu gotowości w zadaniu w tle
BackgroundTaskBuilder i powiązane interfejsy API umożliwiają spakowanym aplikacjom klasycznym uruchamianie zadań w tle. Interfejs API teraz rozszerza te możliwości, aby umożliwić aplikacjom wykonywanie kodu w trybie nowoczesnego uśpienia. Aktualizacja dodaje również właściwości, które mogą być odpytywane przez aplikację, aby określić, czy system ograniczy zadania w tle dla aplikacji w nowoczesnej trybie wstrzymania, aby zaoszczędzić żywotność baterii. Umożliwia to scenariusze takie jak aplikacje odbierające połączenia VoIP lub inne powiadomienia push z nowoczesnego trybu wstrzymania.
Uwaga / Notatka
"Spakowane aplikacje klasyczne" w tej sekcji odnosi się do aplikacji klasycznych Win32, które mają tożsamość pakietu (tj. są aplikacjami mostka klasycznego lub aplikacjami o małej objętości z podpisanym pakietem) i mają główną (lub wmain) funkcję jako punkt startowy.
W poniższym przykładzie pokazano, jak deweloper aplikacji może użyć interfejsu API BackgroundTaskBuilder do zarejestrowania co najwyżej jednego zadania o określonej nazwie zadania. W przykładzie pokazano również, jak sprawdzić i wybrać rejestrację zadań do uruchamiania w nowoczesnym trybie gotowości dla najważniejszych zadań aplikacji.
// The following namespace is required for BackgroundTaskBuilder APIs.
using Windows.ApplicationModel.Background;
// The following namespace is required for API version checks.
using Windows.Foundation.Metadata;
// The following namespace is used for showing Toast Notifications. This
// namespace requires the Microsoft.Toolkit.Uwp.Notifications NuGet package
// version 7.0 or greater.
using Microsoft.Toolkit.Uwp.Notifications;
// Incoming calls are considered to be critical tasks to the operation of the app.
const string IncomingCallTaskName = "IncomingCallTask";
const string NotificationTaskName = "NotificationTask";
const string PrefetchTaskName = "PrefetchTask";
public static bool IsAllowedInBackground(BackgroundAccessStatus status) {
return ((status != BackgroundAccessStatus.Denied) &&
(status != BackgroundAccessStatus.DeniedBySystemPolicy) &&
(status != BackgroundAccessStatus.DeniedByUser) &&
(status != BackgroundAccessStatus.Unspecified));
}
public async void RegisterTask(IBackgroundTrigger trigger,
Guid entryPointClsid,
string taskName,
bool isRunInStandbyRequested)
{
var taskBuilder = new BackgroundTaskBuilder();
taskBuilder.SetTrigger(trigger);
taskBuilder.SetTaskEntryPointClsid(entryPointClsid);
// Only the most critical background work should be allowed to proceed in
// modern standby. Additionally, some platforms may not support modern
// or running background tasks in modern standby at all. Only attempt to
// request modern standby execution if both are true. Requesting network
// is necessary when running in modern standby to handle push notifications.
if (IsRunInStandbyRequested && taskBuilder.IsRunningTaskInStandbySupported)
{
var accessStatus = BackgroundExecutionManager.GetAccessStatusForModernStandby();
if (!IsAllowedInBackground(accessStatus)
{
await BackgroundExecutionManager.RequestAccessKindForModernStandby(
BackgroundAccessRequestKind.AllowedSubjectToSystemPolicy,
"This app wants to receive incoming notifications while your device is asleep");
}
accessStatus = BackgroundExecutionManager.GetAccessStatusForModernStandby();
if (IsAllowedInBackground(accessStatus)
{
taskBuilder.IsRunningTaskInStandbyRequested = true;
taskBuilder.IsNetworkRequested = true;
}
}
// Check that the registration is valid before attempting to register.
if (taskBuilder.IsRegistrationValid)
{
// If a task with the specified name already exists, it is unregistered
// before a new one is registered. Note this API may still fail from
// catastrophic failure (e.g., memory allocation failure).
taskBuilder.Register(taskName);
}
return;
}
RegisterTask(new PushNotificationTrigger(), "{INSERT-YOUR-GUID-HERE}", IncomingCallTaskName, true);
Sprawdź, czy zadania w tle przekroczyły budżet w nowoczesnej gotowości
Poniższy przykładowy kod pokazuje, jak deweloper aplikacji może używać elementu BackgroundWorkCost.WasApplicationThrottledInStandby i BackgroundWorkCost.ApplicationEnergyUseLevel, aby monitorować i reagować na wyczerpanie budżetu aplikacji w tle. Deweloper aplikacji może reagować, redukując zadania o niższym priorytecie w trybie nowoczesnej gotowości. Należy pamiętać, że opiera się to na kodzie z poprzedniego przykładu.
public async void ReduceBackgroundCost()
{
BackgroundTaskRegistration callTask;
BackgroundTaskRegistration notificationTask;
BackgroundTaskRegistration prefetchTask;
// Nothing to do if the app was not or will not be throttled.
if (!BackgroundWorkCost.WasApplicationThrottledInStandby &&
(BackgroundWorkCost.ApplicationEnergyUseLevel != StandbyEnergyUseLevel.OverBudget))
{
return;
}
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
switch (task.Value.Name) {
case IncomingCallTaskName:
callTask = task.Value;
break;
case NotificationTaskName:
notificationTask = task.Value;
break;
case PrefetchTaskName:
prefetchTask = task.Value;
break;
default:
}
}
if (callTask.WasTaskThrottledInStandby)
{
// Unset the throttle flag after acknowledging it so the app can
// react to the same task being throttled again in the future.
task.Value.WasTaskThrottledInStandby = false;
// Notify the user that the notification was missed.
new ToastContentBuilder()
.AddText("You missed a call")
.AddText(task.Value.Name)
.Show();
// Because the incoming calls were not activated, demote less notifications
// tasks so the calls can be delivered promptly in the future.
RegisterTask(notificationTask.Value.Trigger,
typeof(TimeTriggeredTask).GUID,
notificationTask.Value.Name,
false);
}
// Note that if incoming call tasks were throttled in some previous modern
// standby session, the application energy use was over budget for some period.
// Demote unimportant tasks like prefetch work to avoid calls and notifications
// from being throttled.
if (callTask.WasTaskThrottledInStandby) ||
(BackgroundWorkCost.ApplicationEnergyUseLevel == StandbyEnergyUseLevel.OverBudget))
{
RegisterTask(prefetchTask.Value.Trigger,
typeof(TimeTriggeredTask).GUID,
prefetchTask.Value.Name,
false);
}
return;
}
Monitorowanie trendów zużycia energii zadań w tle
Poniżej przedstawiono przyrostową aktualizację do następującego przykładowego kodu C++WinRT/C# na GitHub.
W przykładzie pokazano, jak za pomocą BackgroundWorkCost.ApplicationEnergyUseTrend monitorować, jak zadania w tle zmierzają do wyczerpania swojego budżetu. Możesz również zatrzymać uruchamianie najdroższych zadań w tle oraz uniemożliwić uruchamianie tych zadań podczas nowoczesnej gotowości, jeśli aplikacja zbyt szybko wykorzystuje przeznaczony na nie budżet. Ten przykład opiera się na kodzie z poprzednich przykładów.
public async void ReduceBackgroundCostPreemptively()
{
BackgroundTaskRegistration mostExpensiveTask = null;
// We can't do anything preemptively since the trend isn't known.
if (!BackgroundWorkCost.IsApplicationEnergyUseTrendKnown)
{
return;
}
// The app is not trending towards being over budget, so this method can
// return early.
if ((BackgroundWorkCost.ApplicationEnergyUseTrend != EnergyUseTrend.OverBudget) &&
(BackgroundWorkCost.ApplicationEnergyUseTrend != EnergyUseTrend.OverHalf))
{
return;
}
// The application is going exceeding its budget very quickly. Demote the
// most expensive task that is not the call task before call tasks start being
// throttled.
if (BackgroundWorkCost.ApplicationEnergyUseTrend == EnergyUseTrend.OverBudget)
{
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
if ((task.Value.Name != IncomingCallTaskName) &&
((mostExpensiveTask == null) ||
(mostExpensiveTask.ApplicationEnergyUseTrendContributionPercentage <
task.Value.ApplicationEnergyUseTrendContributionPercentage)))
{
mostExpensiveTask = task.Value;
}
}
}
if (mostExpensiveTask != null)
{
RegisterTask(mostExpensiveTask.Trigger,
typeof(TimeTriggeredTask).GUID,
mostExpensiveTask.Name,
false);
}
// The application is trending toward eventually exceeding its budget. Demote the
// least important prefetch task before calls and notifications are throttled.
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
if (task.Value.Name == PrefetchTaskName) {
RegisterTask(task.Value.Trigger,
typeof(TimeTriggeredTask).GUID,
task.Value.Name,
false);
}
}
return;
}
Zadania w tle i łączność sieciowa
Jeśli zadanie w tle wymaga łączności sieciowej, należy pamiętać o następujących kwestiach.
Wyzwalacze związane z siecią
- Użyj SocketActivityTrigger, aby aktywować zadanie w tle, gdy zostanie odebrany pakiet i należy wykonać zadanie krótkotrwałe. Po wykonaniu zadania zadanie w tle powinno zakończyć się w celu zaoszczędzenia zasilania.
- Użyj obiektu ControlChannelTrigger, aby aktywować zadanie w tle po odebraniu pakietu, gdy musisz wykonać długotrwałe zadanie.
Warunki i flagi związane z siecią
- Dodaj warunek InternetAvailable (BackgroundTaskBuilder.AddCondition) do zadania w tle, aby opóźnić wyzwalanie zadania w tle do momentu uruchomienia stosu sieciowego. Ten warunek pozwala zaoszczędzić energię, ponieważ zadanie w tle nie zostanie wykonane, dopóki dostęp do sieci nie będzie dostępny. Ten warunek nie zapewnia aktywacji w czasie rzeczywistym.
- Niezależnie od używanego wyzwalacza ustaw wartość IsNetworkRequested w zadaniu w tle, aby upewnić się, że sieć pozostaje uruchomiona podczas uruchamiania zadania w tle. To mówi infrastrukturze zadań w tle, aby utrzymywała połączenie sieciowe podczas wykonywania zadania, nawet jeśli urządzenie weszło w tryb podtrzymania połączenia. Jeśli zadanie w tle nie używa funkcji IsNetworkRequested, zadanie w tle nie będzie mogło uzyskać dostępu do sieci w trybie wstrzymania połączonego.