Crear servicios de Android

En esta guía se describen los servicios de Xamarin.Android, que son componentes de Android que permiten realizar el trabajo sin una interfaz de usuario activa. Los servicios se utilizan con mucha frecuencia para tareas que se realizan en segundo plano, como cálculos que requieren mucho tiempo, descarga de archivos, reproducción de música, etc. Explica los distintos escenarios para los que son adecuados los servicios y muestra cómo implementarlos tanto para realizar tareas en segundo plano de larga duración como para proporcionar una interfaz para llamadas a procedimientos remotos.

Información general de Android Services

Las aplicaciones móviles no son como las aplicaciones de escritorio. Los escritorios disponen de una gran cantidad de recursos, como pantalla, memoria, espacio de almacenamiento y una fuente de alimentación conectada, pero los dispositivos móviles no. Estas limitaciones obligan a las aplicaciones móviles a comportarse de forma diferente. Por ejemplo, la pantalla pequeña de un dispositivo móvil normalmente significa que solo una aplicación (es decir, Actividad) está visible a la vez. Las demás actividades pasan a un segundo plano y se suspenden, por lo que no pueden realizar ninguna tarea. Sin embargo, solo porque una aplicación Android está en segundo plano no significa que sea imposible que la aplicación siga funcionando.

Las aplicaciones Android se componen de al menos uno de los siguientes cuatro componentes principales: Actividades, Receptores de emisiones, Proveedores de contenidos y Servicios. Las actividades son la piedra angular de muchas grandes aplicaciones Android porque proporcionan la interfaz de usuario que permite a un usuario interactuar con la aplicación. Sin embargo, cuando se trata de realizar trabajos simultáneos o en segundo plano, las actividades no siempre son la mejor opción.

El mecanismo principal para el trabajo en segundo plano en Android es el servicio. Un servicio Android es un componente diseñado para realizar algún trabajo sin una interfaz de usuario. Un servicio puede descargar un archivo, reproducir música o aplicar un filtro a una imagen. Los servicios también se pueden usar para la comunicación entre procesos (IPC) entre aplicaciones Android. Por ejemplo, una aplicación Android podría usar el servicio reproductor de música que procede de otra aplicación o una aplicación podría exponer datos (como la información de contacto de una persona) a otras aplicaciones a través de un servicio.

Los servicios, y su capacidad para realizar tareas en segundo plano, son cruciales para ofrecer una interfaz de usuario fluida y sin problemas. Todas las aplicaciones Android tienen un subproceso principal (también conocido como subproceso UI ) en el que se ejecutan las Actividades. Para mantener la capacidad de respuesta del dispositivo, Android debe poder actualizar la interfaz de usuario a la velocidad de 60 fotogramas por segundo. Si una aplicación Android realiza demasiado trabajo en el subproceso principal, Android perderá fotogramas, lo que a su vez provoca que la interfaz de usuario aparezca entrecortada (también conocido como janky). Esto significa que cualquier trabajo realizado en el subproceso de interfaz de usuario debe completarse en el intervalo de tiempo entre dos fotogramas, aproximadamente 16 milisegundos (1 segundo cada 60 fotogramas).

Para solucionar este problema, un desarrollador puede usar subprocesos en una actividad para realizar algún trabajo que bloquearía la interfaz de usuario. Sin embargo, esto podría causar problemas. Es muy posible que Android destruya y vuelva a crear las varias instancias de la actividad. Sin embargo, Android no destruirá automáticamente los subprocesos, lo que podría provocar pérdidas de memoria. Un buen ejemplo de esto es cuando se gira el dispositivo, Android intentará destruir la instancia de la Actividad y luego recrear una nueva:

When device rotates, instance 1 is destroyed and instance 2 is created

Esto es una potencial pérdida de memoria el subproceso creado por la primera instancia de la Actividad seguirá ejecutándose. Si el subproceso tiene una referencia a la primera instancia de la Actividad, esto evitará que Android recoja el objeto de la basura. Sin embargo, se sigue creando la segunda instancia de la Actividad (que a su vez podría crear un nuevo hilo). Girar el dispositivo varias veces en rápida sucesión puede agotar toda la RAM y obligar a Android a finalizar toda la aplicación para recuperar memoria.

Como regla general, si el trabajo a realizar debe sobrevivir a una Actividad, entonces debe crearse un servicio para realizar ese trabajo. Sin embargo, si el trabajo solo es aplicable en el contexto de una Actividad, entonces crear un subproceso para realizar el trabajo podría ser más apropiado. Por ejemplo, la creación de una miniatura para una foto que se acaba de agregar a una aplicación de galería de fotos probablemente debería producirse en un servicio. Por ejemplo, la creación de una miniatura para una foto que se acaba de agregar a una aplicación de galería de fotos probablemente debería producirse en un servicio.

El trabajo en segundo puede dividirse en dos grandes categorías:

  1. Tarea de ejecución de larga duración: este es el trabajo que está en curso hasta que se detiene explícitamente. Un ejemplo de un tarea de larga duración es una aplicación que transmite música o que debe supervisar los datos recopilados de un sensor. Estas tareas deben ejecutarse aunque la aplicación no tenga ninguna interfaz de usuario visible.
  2. Tareas periódicas: (a veces denominadas trabajos) Una tarea periódica es aquella que tiene una duración relativamente corta (varios segundos) y se ejecuta según un programa (es decir, una vez al día durante una semana o quizás solo una vez en los próximos 60 segundos). Un ejemplo de esto es descargar un archivo desde Internet o generar una miniatura para una imagen.

Existen cuatro tipos diferentes de servicios Android:

  • Servicio enlazado: Un servicio enlazado es un servicio que tiene algún otro componente (típicamente una Actividad) enlazado a él. Un servicio enlazado proporciona una interfaz que permite que el componente enlazado y el servicio interactúen entre sí. Una vez que no haya más clientes enlazados al servicio, Android cerrará el servicio.

  • IntentService: un IntentService es una subclase especializada de la clase Service que simplifica la creación y el uso del servicio. Un IntentService está destinado a manipular llamadas autónomas individuales. A diferencia de un servicio, que puede administrar varias llamadas simultáneamente, un IntentService es más parecido a un procesador de colas de trabajo: el trabajo se pone en cola y un IntentService procesa cada trabajo de uno en uno en un único subproceso de trabajo. Normalmente, un IntentService no está enlazado a una actividad o a un fragmento.

  • Servicio Iniciado: un servicio iniciado es un servicio que ha sido iniciado por algún otro componente de Android (como una Actividad) y se ejecuta continuamente en segundo plano hasta que algo explícitamente le dice al servicio que se detenga. A diferencia de un servicio enlazado, un servicio iniciado no tiene ningún cliente enlazado directamente a él. Por este motivo, es importante diseñar los servicios iniciados de modo que puedan reiniciarse correctamente cuando sea necesario.

  • Servicio híbrido: un servicio híbrido es un servicio que tiene las características de un servicio iniciado y de un servicio enlazado. Un servicio híbrido se puede iniciar cuando un componente se enlaza a él o puede iniciarse mediante algún evento. Un componente cliente puede o no estar enlazado al servicio híbrido. Un servicio híbrido seguirá funcionando hasta que se le indique explícitamente que se detenga, o hasta que no haya más clientes enlazados a él.

El tipo de servicio a utilizar depende en gran medida de los requisitos de la aplicación. Como regla general, un IntentService o un servicio enlazado son suficientes para la mayoría de las tareas que debe realizar una aplicación Android, por lo que se debe dar preferencia a uno de esos dos tipos de servicios. Un IntentService es una buena opción para tareas "puntuales", como la descarga de un archivo, mientras que un servicio enlazado sería adecuado cuando se requieren interacciones frecuentes con una Actividad/Fragmento.

Aunque la mayoría de los servicios se ejecutan en segundo plano, existe una subcategoría especial conocida como servicio en primer plano. Se trata de un servicio al que se da mayor prioridad (en comparación con un servicio normal) para que realice algún trabajo para el usuario (como reproducir música).

También es posible ejecutar un servicio en su propio proceso en el mismo dispositivo, lo que a veces se denomina servicio remoto o servicio fuera de proceso. Esto requiere más esfuerzo de creación, pero puede ser útil para cuando una aplicación necesita compartir funcionalidad con otras aplicaciones, y puede, en algunos casos, mejorar la experiencia de usuario de una aplicación.

Límites de ejecución en segundo plano en Android 8.0

A partir de Android 8.0 (nivel de API 26), una aplicación Android ya no podrá ejecutarse libremente en segundo plano. Cuando está en primer plano, una aplicación puede iniciar y ejecutar servicios sin restricciones. Cuando una aplicación pasa a segundo plano, Android le concede cierto tiempo para iniciar y utilizar los servicios. Una vez transcurrido ese tiempo, la aplicación ya no podrá iniciar ningún servicio y los servicios que se hayan iniciado se cerrarán. En este punto no es posible que la aplicación realice ningún trabajo. Android considera que una aplicación está en primer plano si se cumple una de las siguientes condiciones:

  • Hay una actividad visible (iniciada o en pausa).
  • La aplicación ha iniciado un servicio en primer plano.
  • Otra aplicación está en primer plano y usa componentes de una aplicación que, de otro modo, estaría en segundo plano. Un ejemplo de esto es si la Aplicación A, que está en primer plano, está enlazada a un servicio proporcionado por la Aplicación B. La Aplicación B también sería considerada en primer plano, y no finalizada por Android por estar en segundo plano.

Hay algunas situaciones en las que, aunque una aplicación está en segundo plano, Android reactivará la aplicación y relajará estas restricciones durante unos minutos, lo que permite que la aplicación realice algún trabajo:

  • La aplicación recibe un mensaje de Firebase Cloud de alta prioridad.
  • La aplicación recibe una difusión.
  • La aplicación recibe y ejecuta un PendingIntent en respuesta a una notificación.

Es posible que las aplicaciones de Xamarin.Android existentes tengan que cambiar la forma en que realizan el trabajo en segundo plano para evitar cualquier problema que pueda surgir en Android 8.0. Estas son algunas alternativas prácticas a un servicio Android:

  • Programar el trabajo para que se ejecute en segundo plano utilizando el Programador de trabajos de Android o el Dispatcher de trabajos de Firebase: estas dos bibliotecas proporcionan un marco para que las aplicaciones segreguen el trabajo en segundo plano en trabajos, una unidad discreta de trabajo. A continuación, las aplicaciones pueden programar el trabajo con el sistema operativo junto con algunos criterios sobre cuándo puede ejecutarse el trabajo.
  • Iniciar el servicio en primer plano: un servicio en primer plano es útil para cuando la aplicación debe realizar alguna tarea en segundo plano y es posible que el usuario tenga que interactuar periódicamente con esa tarea. El servicio en primer plano mostrará una notificación persistente para que el usuario sea consciente de que la aplicación está ejecutando una tarea en segundo plano y también proporciona una forma de supervisar o interactuar con la tarea. Un ejemplo sería una aplicación de podcast que reprodujera un podcast para el usuario o que descargara un episodio de un podcast para poder disfrutarlo más tarde.
  • Usa un mensaje de Firebase Cloud (FCM) de alta prioridad: cuando Android recibe un FCM de alta prioridad para una aplicación, permitirá que esa aplicación ejecute servicios en segundo plano durante un breve periodo de tiempo. Esta sería una buena alternativa a tener un servicio en segundo plano que sondea una aplicación en segundo plano.
  • Aplazar el trabajo para cuando la aplicación pase a primer plano: si ninguna de las soluciones anteriores es viable, las aplicaciones deberán desarrollar su propia forma de pausar y reanudar el trabajo cuando la aplicación pase a primer plano.