> For the complete documentation index, see [llms.txt](https://elguerre.gitbook.io/de0an/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://elguerre.gitbook.io/de0an/capitulo-2-antes-de-comenzar.-el-terreno-de-juego/tareas-en-segundo-plano.md).

# Tareas en segundo plano

Las tareas en segundo plano permiten la ejecución de la aplicación incluso cuando se encuentra suspendida. Generalmente dedicadas a la realización de pequeños trabajos que no requieren la interacción del usuario. Requiere de una serie de pasos básicos:

1. Crear un proyecto de tipo ***Windows Runtime Component***, destinado a la creación de cualquier tipo de tarea para su ejecución en segundo plano.
2. Crear una clase *BackgroundTask.cs*, que implemente la interfaz ***IBackgroundTask*** y, concretamente su método “**Run**”. El siguiente código muestra un ejemplo de esta implementación:

```csharp
namespace ElGuerre.Taskin.BackgroundAgent
{
    public sealed class BackgroundTask : IBackgroundTask
    {
        public async void Run(IBackgroundTaskInstance taskInstance)
        {
            var deferral = taskInstance.GetDeferral();
            // TODO: Hacer algo ...
            deferral.Complete();
        }
    }
}
```

3. Establecer las propiedades de la declaración *Background Tasks*:

![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-93b0527599a5c541c8b12248c9502a6e7116c564%2Fimage58.png?alt=media)

**Figura 40.- Propiedades de una declaración de una tarea en segundo plano**

Una vez completados estos pasos, necesitaremos contar con los permisos del usuario para que una tarea pueda ejecutarse correctamente. Para ello solicitaremos este acceso con algunas líneas de código:

```csharp
BackgroundAccessStatus status = BackgroundExecutionManager.GetAccessStatus();
if (status == BackgroundAccessStatus.Denied || status == BackgroundAccessStatus.Unspecified)
{
    await BackgroundExecutionManager.RequestAccessAsync();
}
```

Cuando se crea una tarea en segundo plano, es necesario determinar en respuesta a que **eventos** será ejecutada y bajo qué condiciones. La creación de un evento, a su vez, además del tipo, necesita un segundo parámetro booleano *OneShot*, que indica al evento si se ejecuta o no sólo la primera vez que se produce. La siguiente tabla muestra la relación entre los tipos más comunes de tareas y cuando son activadas:

**Tabla 18.- Tipos de tareas y cuando son activadas**

| Tipos de tarea                     | Cuando se ejecutan                                                                                                                                                   |
| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SystemTrigger                      | En relación a los eventos específicos listados en la tabla 19.                                                                                                       |
| TimeTrigger                        | Cada cierto periodo de tiempo. Mínimo 15 minutos.                                                                                                                    |
| LocationTrigger                    | Cuando el usuario (con el GPS de su dispositivo activado) entra o sale de un perímetro determinado. A este fenómeno se le conoce como Geoperímetro (o *Geofencing)*. |
| MaintenanceTrigger                 | Periódicamente para hacer trabajos de mantenimiento y siempre, cuando el dispositivo esté conectado a una toma de energía.                                           |
| PushNotificationTrigger            | En respuesta a una notificación *push* tipo *raw* enviada desde el servicio de notificaciones push de Microsoft *WNS* (*Windows Push Notification Service*).         |
| DeviceUsetrigger                   | Inicia una operación de longitud fija y de ejecución prolongada (transferencia o sincronización de contenido) con un dispositivo.                                    |
| ChatMessageNotificationTrigger     | En respuesta a una notificación por un mensaje de texto.                                                                                                             |
| ToastNotificationActionTrigger     | Al recibir una notificación de tipo *Toast*.                                                                                                                         |
| NetworkOperatorNotificationTrigger | Al recibir una notificación de un operador de red móvil.                                                                                                             |
| UserNotificationChangedTrigger     | Tras añadir o eliminar una notificación de usuario. *Disponible a partir del SDK 14332*.                                                                             |

Podemos consultar el resto de tipos de tareas visitando la página: <https://msdn.microsoft.com/en-us/library/windows/apps/windows.applicationmodel.background.aspx>.

**Tabla 19.- Condiciones para un evento de tipo SystemTrigger**

| Eventos                       | Cuando se activan |                                                                                                                                                    |
| ----------------------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| SMSReceived                   |                   | Al recibir un SMS.                                                                                                                                 |
| User Present / Away           |                   | Cuando el usuario esté presente y deje de estarlo.                                                                                                 |
| NetworkStateChange            |                   | Cuando se producen cambios en la red, relativos al coste o la conectividad.                                                                        |
| ControlChannelReset (\*)      |                   | Al recibir datos a través de la red o al enviar a la red paquetes de tipo *keep-alive*. El valor del parámetro *OneShot* deberá ser siempre falso. |
| InternetAvailable             |                   | Cuando hay conexión disponible con internet.                                                                                                       |
| SessionConnected              |                   | Cuando se establece la sesión. Es decir, cuando el usuario se conecta con al dispositivo con su cuenta (Microsoft Id).                             |
| ServicingComplete             |                   | Cuando el sistema ha terminado de actualizar una aplicación.                                                                                       |
| TimeZoneChange                |                   | Al cambiar la zona horaria del dispositivo.                                                                                                        |
| OnlineIdConnectedStateChanged |                   | Cuando la cuenta de Microsoft está conectada a cambios de cuenta.                                                                                  |
| BackgroundWorkCostChange      |                   | Cuando cambia el coste del trabajo de la tarea.                                                                                                    |
| LockScreenApplicationAdded    |                   | Cuando un Tile es añadido a la pantalla de bloqueo.                                                                                                |
| LockScreenApplicationRemoved  |                   | Cuando un tile es eliminado de la pantalla de bloqueo.                                                                                             |

Existen también una serie de condiciones que van a permitir que los eventos se activen o no, y, por consiguiente, que la tarea finalmente sea lanzada o no.

**Tabla 20.- Condiciones para la ejecución de eventos (o triggers)**

| Condición                | Cuando es válida                                   |
| ------------------------ | -------------------------------------------------- |
| BackgroundWorkCostNoHigh | Cuando el coste al trabajo a realizar es bajo.     |
| FreeNetworkAvailable     | Cuando existe una conexión a red sin coste alguno. |
| InternetAvailable        | Cuando el acceso a internet es posible.            |
| InternetNotAvailable     | Cuando el acceso a internet no es posible.         |
| SessionConnected         | Cuando existe una sesión de usuario conectada.     |
| SessionDisconected       | Cuando no existe una sesión de usuario conectada.  |
| UserNotPresent           | Cuando el usuario está ausente.                    |
| UserPresent              | Cuando el usuario está presente.                   |

En la siguiente porción de código puede verse el uso de estos eventos para el ejemplo anterior. En particular para una tarea de tipo *SystemTrigger* y para un tipo de evento *TimeZone*.

```csharp
if (!BackgroundTaskRegistration.AllTasks.Values.Where(v => v.Name == "ePomo3BackgroundTask").Any())
{
    var builder = new BackgroundTaskBuilder();
    builder.Name = TASK_NAME;
    builder.TaskEntryPoint = "elGuerre.ePomo3.BackgroundAgent.BackgroundTask";
    builder.SetTrigger(new SystemTrigger(SystemTriggerType.TimeZoneChange, false););
    BackgroundTaskRegistration registration = builder.Register();
    registration.Completed += (sender, args) => {};
    registration.Progress += (sender, args) => {};
}
```

Para probar que la tarea funciona y se activa correctamente será suficiente con hacer un cambio de zona horaria en el emulador o en el terminal. Sin embargo, cuando estamos depurando, estos cambios de configuración pueden llegar a ser un poco repetitivos e incluso hasta molestos. Para evitarlo seguiremos los siguientes pasos una vez ejecutada la aplicación desde Visual Studio:

1. Acceder al desplegable de eventos de ciclo de vida de la aplicación *Lifecycle Events* que se encuentra en la barra de tareas.
2. Seleccionar la opción que se corresponde con el nombre de nuestra tarea (*TaskinBackgroundTask*):

![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-313d5f38d971d230407eed089390a50e2a3dd6a2%2Fimage59.png?alt=media)

**Figura 41.- Depuración de tareas en segundo plano desde Lifecycle Events en Visual Studio**

El uso de tareas en segundo plano causa impacto en los recursos del sistema tales como CPU, red, etc., así como en la vida de la batería. Se recomienda, por tanto, seguir algunas buenas prácticas sobre su uso:

1. Diseñar la tarea para que se ejecute en el menor tiempo posible.
2. Diseñar la experiencia de usuario para la pantalla de bloqueo.
3. No especificar la propiedad *Executable* para asegurar que la tarea se ejecuta en el host proporcionado por el sistema.
4. En el manifiesto de la aplicación, indicar en la propiedad *Entry Point* el nombre de la clase (incluido su *namespace*) o, en la propiedad *Start Page* el nombre del archivo JavaScript.
5. Escribir trazas para poder verificar aquellos casos en los que la tarea no sea activada/ejecutada.
6. Utilizar el *storage* para compartir información entre la tarea y la aplicación.
7. Registrar los manejadores de progreso, finalización y cancelación en la clase que implementa la tarea.
8. Registrar el manejador de cancelación
9. Registra el evento *ServicingComplete* si se espera actualizar la aplicación.
10. Asegurar que la librería de clases *Windows Runtime Componente* está referenciada en el proyecto principal.
11. Describir los tipos de tareas cuidadosamente en el manifiesto de la aplicación.
12. Verificar si la aplicación tiene que estar o no en la pantalla de bloqueo.
13. Una tarea únicamente mostrará los elementos de interfaz de usuario; *Toast* *Tiles* o *Badges*.
14. Una tarea no debe depender de la interacción del usuario.

{% hint style="info" %}
**Nota**: Para profundizar más sobre este tema, consultar las directrices para la creación de tareas en segundo plano: <https://msdn.microsoft.com/es-es/windows/uwp/launch-resume/guidelines-for-background-tasks>
{% endhint %}
