Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Aprenda cómo crear y registrar una tarea en segundo plano en tu aplicación con la clase BackgroundTaskBuilder de Windows Runtime (WinRT) .
Registrar una tarea en segundo plano
Consulta el ejemplo de BackgroundTask para obtener un ejemplo completo de cómo registrar una tarea en segundo plano en una aplicación para la Plataforma Universal de Windows (UWP).
En el ejemplo siguiente se muestra el registro de una tarea COM de Win32 que se ejecuta en un temporizador periódico de 15 minutos.
Para registrar una tarea en segundo plano, primero debe crear una nueva instancia de la clase BackgroundTaskBuilder. La clase BackgroundTaskBuilder
se usa para crear y registrar tareas en segundo plano en la aplicación. En el ejemplo de código siguiente se muestra cómo crear una nueva instancia de la clase BackgroundTaskBuilder
:
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);
El método RegisterBackgroundTaskWithSystem
toma tres parámetros:
-
trigger
: desencadenador que iniciará la tarea en segundo plano. -
entryPointClsid
: identificador de clase del punto de entrada de tarea en segundo plano. -
taskName
: El nombre de la tarea en segundo plano.
El método RegisterBackgroundTaskWithSystem
crea una nueva instancia de la clase BackgroundTaskBuilder
y establece el identificador de clase de desencadenador y punto de entrada para la tarea en segundo plano. A continuación, el método registra la tarea en segundo plano con el sistema.
Nota
Esta clase no es ágil, lo que significa que debe tener en cuenta su modelo de subprocesos y el comportamiento de serialización. Para obtener más información, consulta Hilos y Serialización (C++/CX) y Usar objetos de Windows Runtime en un entorno multihilo (.NET).
Controlar el modo de espera moderno en una tarea en segundo plano
El BackgroundTaskBuilder y las API relacionadas ya permiten que las aplicaciones de escritorio empaquetadas ejecuten tareas en segundo plano. La API ahora amplía estas API para permitir que estas aplicaciones ejecuten código en modo de espera moderno. La actualización también agrega propiedades que una aplicación puede consultar para determinar si el sistema limitará las tareas en segundo plano de la aplicación en espera moderna para conservar la vida útil de la batería. Esto permite escenarios como las aplicaciones que reciben llamadas VoIP u otras notificaciones push desde el modo de espera moderno.
Nota
"Aplicaciones de escritorio empaquetadas" en esta sección hace referencia a las aplicaciones Win32 que tienen identidad de paquete (es decir, son puente de escritorio o aplicaciones empaquetadas dispersas) y tienen una función principal (o wmain) como punto de entrada.
En el ejemplo siguiente se muestra cómo un desarrollador de aplicaciones puede usar la API BackgroundTaskBuilder para registrar como máximo una tarea con el nombre de tarea especificado. En el ejemplo también se muestra cómo comprobar y participar en el registro de tareas para ejecutarse en modo de espera moderno para las tareas más críticas de la aplicación.
// 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);
Compruebe si las tareas en segundo plano han superado su presupuesto en modo de espera moderno
El código de ejemplo siguiente muestra cómo un desarrollador de aplicaciones puede usar el BackgroundWorkCost.WasApplicationThrottledInStandby y BackgroundWorkCost.ApplicationEnergyUseLevel para supervisar y reaccionar a que sus tareas en segundo plano agoten su presupuesto de la aplicación. El desarrollador de la aplicación puede reaccionar reduciendo el trabajo de prioridad más baja que se realiza en modo de espera moderno. Tenga en cuenta que esto se basa en el código del ejemplo anterior.
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;
}
Supervisar tendencias de uso de energía de tareas en segundo plano
A continuación se muestra una actualización incremental de un extremo a otro al siguiente código de ejemplo de C++WinRT/C# en GitHub.
En el ejemplo se muestra cómo se puede usar el BackgroundWorkCost.ApplicationEnergyUseTrend para supervisar la tendencia de las tareas en segundo plano que tienden a agotar su presupuesto. También puede impedir que las tareas en segundo plano más costosas se ejecuten en espera moderna y evitar que las tareas en segundo plano se ejecuten en modo de espera moderno si su aplicación usa su presupuesto demasiado rápido. Este ejemplo se basa en el código de los ejemplos anteriores.
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;
}
Tareas en segundo plano y conectividad de red
Si la tarea en segundo plano requiere conectividad de red, tenga en cuenta las consideraciones siguientes.
Desencadenadores relacionados con la red
- Usa un SocketActivityTrigger para activar la tarea en segundo plano cuando se recibe un paquete y necesitas realizar una tarea de corta duración. Después de realizar la tarea, la tarea en segundo plano debe finalizar para ahorrar energía.
- Use un ControlChannelTrigger para activar la tarea en segundo plano cuando se recibe un paquete y debe realizar una tarea de larga duración.
Condiciones y marcas relacionados con la red
- Agregue la condición InternetAvailable (BackgroundTaskBuilder.AddCondition) a la tarea en segundo plano para retrasar el desencadenamiento de la tarea en segundo plano hasta que se ejecute la pila de red. Esta condición ahorra energía porque la tarea en segundo plano no se ejecutará hasta que esté disponible el acceso a la red. Esta condición no proporciona activación en tiempo real.
- Independientemente del desencadenador que use, establezca IsNetworkRequested en la tarea en segundo plano para asegurarse de que la red permanece activa mientras se ejecuta la tarea en segundo plano. Esto indica a la infraestructura de tareas en segundo plano que mantenga la red activa mientras se ejecuta la tarea, incluso si el dispositivo ha entrado en modo de espera conectado. Si su tarea en segundo plano no usa IsNetworkRequested, su tarea en segundo plano no podrá acceder a la red cuando esté en modo de espera conectado.