Création de services Android

Ce guide décrit les services Xamarin.Android, qui sont des composants Android qui permettent d’effectuer le travail sans interface utilisateur active. Les services sont très couramment utilisés pour les tâches effectuées en arrière-plan, telles que les calculs chronophages, le téléchargement de fichiers, la lecture de musique, etc. Il explique les différents scénarios auxquels les services sont adaptés et montre comment les implémenter à la fois pour effectuer des tâches en arrière-plan de longue durée et pour fournir une interface pour les appels de procédure à distance.

Vue d’ensemble des services Android

Les applications mobiles ne sont pas comme les applications de bureau. Les ordinateurs de bureau disposent de quantités abondantes de ressources telles que l’immobilier de l’écran, la mémoire, l’espace de stockage et une alimentation connectée, ce qui n’est pas le cas des appareils mobiles. Ces contraintes forcent les applications mobiles à se comporter différemment. Par exemple, le petit écran d’un appareil mobile signifie généralement qu’une seule application (par exemple, Activité) est visible à la fois. Les autres activités sont déplacées vers l’arrière-plan et poussées dans un état suspendu où elles ne peuvent effectuer aucun travail. Toutefois, le simple fait qu’une application Android se trouve en arrière-plan ne signifie pas qu’il est impossible pour l’application de continuer à fonctionner.

Les applications Android sont constituées d’au moins l’un des quatre composants principaux suivants : Activités, Récepteurs de diffusion, Fournisseurs de contenu et Services. Les activités sont la pierre angulaire de nombreuses applications Android, car elles fournissent l’interface utilisateur qui permet à un utilisateur d’interagir avec l’application. Toutefois, lorsqu’il s’agit d’effectuer un travail simultané ou en arrière-plan, les activités ne sont pas toujours le meilleur choix.

Le principal mécanisme pour le travail en arrière-plan dans Android est le service. Un service Android est un composant conçu pour effectuer un travail sans interface utilisateur. Un service peut télécharger un fichier, lire de la musique ou appliquer un filtre à une image. Les services peuvent également être utilisés pour la communication interprocessus (IPC) entre les applications Android. Par exemple, une application Android peut utiliser le service de lecteur de musique provenant d’une autre application ou une application peut exposer des données (telles que les informations de contact d’une personne) à d’autres applications via un service.

Les services, et leur capacité à effectuer un travail en arrière-plan, sont essentiels pour fournir une interface utilisateur fluide et fluide. Toutes les applications Android ont un thread main (également appelé thread d’interface utilisateur) sur lequel les activités sont exécutées. Pour que l’appareil reste réactif, Android doit être en mesure de mettre à jour l’interface utilisateur au rythme de 60 images par seconde. Si une application Android effectue trop de travail sur le thread main, Android supprime les images, ce qui à son tour fait paraître l’interface utilisateur saccadé (parfois appelée janky). Cela signifie que tout travail effectué sur le thread d’interface utilisateur doit se terminer dans l’intervalle de temps entre deux images, soit environ 16 millisecondes (1 seconde toutes les 60 images).

Pour résoudre ce problème, un développeur peut utiliser des threads dans une activité pour effectuer un travail qui bloquerait l’interface utilisateur. Toutefois, cela peut causer des problèmes. Il est très possible qu’Android détruise et recrée les instances multiples de l’activité. Toutefois, Android ne détruit pas automatiquement les threads, ce qui peut entraîner des fuites de mémoire. Un bon exemple de cela est lorsque l’appareil est pivoté : Android tente de détruire les instance de l’activité, puis d’en recréer une nouvelle :

Lorsque l’appareil pivote, instance 1 est détruit et instance 2 est créé

Il s’agit d’une fuite de mémoire potentielle : le thread créé par le premier instance de l’activité est toujours en cours d’exécution. Si le thread contient une référence à la première instance de l’activité, cela empêche Android de récupérer l’objet. Toutefois, la deuxième instance de l’activité est toujours créée (ce qui peut à son tour créer un nouveau thread). La rotation de l’appareil plusieurs fois dans une succession rapide peut épuiser toute la RAM et forcer Android à arrêter l’ensemble de l’application pour récupérer de la mémoire.

En règle générale, si le travail à effectuer doit survivre à une activité, un service doit être créé pour effectuer ce travail. Toutefois, si le travail s’applique uniquement dans le contexte d’une activité, la création d’un thread pour effectuer le travail peut être plus appropriée. Par exemple, la création d’une miniature pour une photo qui vient d’être ajoutée à une application de galerie de photos doit probablement se produire dans un service. Toutefois, un thread peut être plus approprié pour lire de la musique qui ne doit être entendue que lorsqu’une activité est au premier plan.

Le travail en arrière-plan peut être divisé en deux grandes classifications :

  1. Tâche longue durée : il s’agit d’un travail en cours jusqu’à ce qu’il soit explicitement arrêté. Une application qui diffuse de la musique ou qui doit surveiller les données collectées à partir d’un capteur est un exemple de tâche de longue durée . Ces tâches doivent s’exécuter même si l’application n’a pas d’interface utilisateur visible.
  2. Tâches périodiques : (parfois appelée travail) Une tâche périodique est une tâche qui est d’une durée relativement courte (plusieurs secondes) et qui est exécutée selon une planification (c’est-à-dire une fois par jour pendant une semaine ou peut-être une seule fois dans les 60 prochaines secondes). Par exemple, le téléchargement d’un fichier à partir d’Internet ou la génération d’une miniature pour une image.

Il existe quatre types différents de services Android :

  • Service lié : un service lié est un service qui a un autre composant (généralement une activité) lié à celui-ci. Un service lié fournit une interface qui permet au composant lié et au service d’interagir entre eux. Une fois qu’il n’y a plus de clients liés au service, Android arrête le service.

  • IntentService : un IntentService est une sous-classe spécialisée de la classe qui simplifie la Service création et l’utilisation du service. Un IntentService est destiné à gérer des appels autonomes individuels. Contrairement à un service, qui peut gérer simultanément plusieurs appels, un IntentService est plus semblable à un processeur de file d’attente de travail : le travail est mis en file d’attente et un IntentService travail traite chaque travail un par un sur un seul thread de travail. En règle générale, unIntentService n’est pas lié à une activité ou à un fragment.

  • Service démarré : un service démarré est un service qui a été démarré par un autre composant Android (par exemple, une activité) et qui est exécuté en continu en arrière-plan jusqu’à ce que quelque chose indique explicitement au service de s’arrêter. Contrairement à un service lié, un service démarré n’a pas de clients directement liés à celui-ci. Pour cette raison, il est important de concevoir les services démarrés afin qu’ils puissent être correctement redémarrés si nécessaire.

  • Service hybride : un service hybride est un service qui a les caractéristiques d’un service démarré et d’un service lié. Un service hybride peut être démarré par lorsqu’un composant se lie à celui-ci ou qu’il peut être démarré par un événement. Un composant client peut être lié ou non au service hybride. Un service hybride continue de s’exécuter jusqu’à ce qu’il soit explicitement dit de s’arrêter, ou jusqu’à ce qu’il n’y ait plus de clients liés.

Le type de service à utiliser dépend beaucoup des exigences de l’application. En règle générale, un IntentService service ou lié est suffisant pour la plupart des tâches qu’une application Android doit effectuer. La préférence doit donc être donnée à l’un de ces deux types de services. Un IntentService est un bon choix pour les tâches « one-shot », telles que le téléchargement d’un fichier, tandis qu’un service lié convient lorsque des interactions fréquentes avec une activité/fragment sont requises.

Bien que la plupart des services s’exécutent en arrière-plan, il existe une sous-catégorie spéciale appelée service de premier plan. Il s’agit d’un service qui reçoit une priorité plus élevée (par rapport à un service normal) pour effectuer un travail pour l’utilisateur (par exemple, lire de la musique).

Il est également possible d’exécuter un service dans son propre processus sur le même appareil, parfois appelé service distant ou service hors processus. Cela nécessite plus d’efforts pour créer, mais peut être utile lorsqu’une application a besoin de partager des fonctionnalités avec d’autres applications et peut, dans certains cas, améliorer l’expérience utilisateur d’une application.

Limites d’exécution en arrière-plan dans Android 8.0

À compter d’Android 8.0 (niveau API 26), une application Android n’a plus la possibilité de s’exécuter librement en arrière-plan. Au premier plan, une application peut démarrer et exécuter des services sans restriction. Lorsqu’une application passe en arrière-plan, Android lui accorde un certain temps pour démarrer et utiliser les services. Une fois ce temps écoulé, l’application ne peut plus démarrer les services et tous les services démarrés sont arrêtés. À ce stade, il n’est pas possible pour l’application d’effectuer un travail quelconque. Android considère qu’une application est au premier plan si l’une des conditions suivantes est remplie :

  • Il existe une activité visible (démarrée ou suspendue).
  • L’application a démarré un service de premier plan.
  • Une autre application est au premier plan et utilise des composants d’une application qui seraient autrement en arrière-plan. Par exemple, si l’application A, qui se trouve au premier plan, est liée à un service fourni par l’application B. L’application B est alors également considérée au premier plan et non terminée par Android pour être en arrière-plan.

Il existe certaines situations où, même si une application est en arrière-plan, Android réveille l’application et assouplit ces restrictions pendant quelques minutes, ce qui permet à l’application d’effectuer un certain travail :

  • Un message cloud Firebase de haute priorité est reçu par l’application.
  • L’application reçoit une diffusion.
  • L’application reçoit et exécute un PendingIntent en réponse à une notification.

Les applications Xamarin.Android existantes peuvent devoir modifier la façon dont elles effectuent un travail en arrière-plan pour éviter tout problème pouvant survenir sur Android 8.0. Voici quelques alternatives pratiques à un service Android :

  • Planifier le travail à exécuter en arrière-plan à l’aide du planificateur de travaux Android ou du répartiteur de travaux Firebase : ces deux bibliothèques fournissent une infrastructure permettant aux applications de séparer le travail en arrière-plan dans les travaux, une unité de travail discrète. Les applications peuvent ensuite planifier le travail avec le système d’exploitation, ainsi que certains critères concernant le moment où le travail peut s’exécuter.
  • Démarrez le service au premier plan : un service de premier plan est utile lorsque l’application doit effectuer une tâche en arrière-plan et que l’utilisateur peut avoir besoin d’interagir régulièrement avec cette tâche. Le service de premier plan affiche une notification persistante afin que l’utilisateur sache que l’application exécute une tâche en arrière-plan et fournit également un moyen de surveiller ou d’interagir avec la tâche. Par exemple, une application de podcasting qui lit un podcast à l’utilisateur ou peut-être télécharge un épisode de podcast afin qu’il puisse être apprécié plus tard.
  • Utiliser un message cloud Firebase (FCM) à haute priorité : quand Android reçoit un FCM de haute priorité pour une application, il permet à cette application d’exécuter des services en arrière-plan pendant une courte période. Il s’agit d’une bonne alternative à un service en arrière-plan qui interroge une application en arrière-plan.
  • Différer le travail pour lorsque l’application entre au premier plan : si aucune des solutions précédentes n’est viable, les applications doivent développer leur propre façon de suspendre et de reprendre le travail lorsque l’application arrive au premier plan.