Présentation des services

Un Service est un composant d'application qui peut effectuer des opérations de longue durée en arrière-plan. Il ne fournit pas d'interface utilisateur. Une fois démarré, un service peut continuer à fonctionner pendant un certain temps, même après que l'utilisateur est passé à un autre application. De plus, un composant peut se lier à un service pour interagir avec lui et même effectuer la communication inter-processus (IPC). Par exemple, un service peut gérer des transactions réseau, lire de la musique, effectuer des E/S de fichiers ou interagir avec un fournisseur de contenu, le tout en arrière-plan.

Attention:Un service s'exécute dans le thread principal de son hébergement processus ; le service ne crée pas son propre thread et ne peut pas s'exécuter dans un processus distinct, sauf indication contraire. Vous devez exécuter toutes les opérations bloquantes sur un thread distinct au sein du service pour éviter qu'une application Erreurs ANR (Pas de réponse).

Types de services

Voici les trois différents types de services:

Premier plan

Un service de premier plan effectue une opération visible pour utilisateur. Par exemple, une application audio utilise un service de premier plan pour lire la piste audio. Les services de premier plan doivent afficher une notification. Les services de premier plan continuent de s'exécuter même lorsque l'utilisateur n'interagit pas avec l'application.

Lorsque vous utilisez un service de premier plan, vous devez afficher une notification pour que les utilisateurs savent activement que le service est en cours d'exécution. Cette notification ne peut pas peuvent être ignorées, sauf si le service est soit arrêté, soit supprimé au premier plan.

En savoir plus sur la configuration services de premier plan dans votre l'application.

Remarque:La L'API WorkManager offre un moyen flexible de planifier des tâches et est capable de exécuter ces tâches en tant que services de premier plan si nécessaire. Dans de nombreux cas, l'utilisation WorkManager est préférable à l'utilisation directe de services de premier plan.

Arrière-plan
Un service d'arrière-plan effectue une opération qui n'est pas directement remarquée par l'utilisateur. Par exemple, si une application utilise un service pour compacter son espace de stockage, il s'agit généralement d'un service d'arrière-plan.

Remarque:Si votre application cible le niveau d'API 26 ou supérieur, le système impose des restrictions sur l'exécution en arrière-plan. lorsque l'application n'est pas au premier plan. Dans la plupart des cas situations, par exemple, vous ne devez pas accéder aux informations de localisation ou un arrière-plan. À la place, planifier des tâches à l'aide de WorkManager

Associé
Un service est lié lorsqu'un composant d'application s'y lie en appelant bindService(). Un service lié offre un service client-serveur qui permet aux composants d'interagir avec le service, d'envoyer des requêtes, de recevoir des résultats, et même d'un processus à l'autre grâce à la communication inter-processus (IPC). Un service lié s'exécute uniquement tant qu'un autre composant d'application y est lié. Plusieurs composants peuvent être liés service en même temps, mais lorsqu'ils sont tous dissociés, le service est détruit.

Bien que cette documentation traite généralement des services démarrés et liés séparément, votre service peut fonctionner dans les deux sens : il peut être démarré (pour fonctionner indéfiniment) et autoriser liée. Il s'agit simplement d'implémenter deux méthodes de rappel: onStartCommand() pour autoriser les composants à le démarrer et onBind() pour autoriser la liaison.

Que votre service soit démarré, lié ou les deux, tout composant d'application peut utiliser le service (même à partir d'une application distincte) de la même manière que n'importe quel composant une activité, en la démarrant par un Intent. Vous pouvez toutefois déclarer définir le service comme privé dans le fichier manifeste et bloquer l'accès d'autres applications. Ce point est abordé plus en détail dans la section Déclarer le service dans le fichier manifeste.

Choisir entre un service et un thread

Un service est simplement un composant qui peut s'exécuter en arrière-plan, même lorsque l'utilisateur avec votre application. Vous ne devez donc créer un service que s'il s'agit besoin.

Si vous devez effectuer des tâches en dehors de votre thread principal, mais uniquement lorsque l'utilisateur interagit avec votre application, créez plutôt un nouveau thread dans le contexte d'une autre application . Par exemple, si vous voulez écouter de la musique, mais uniquement lorsque votre activité est en cours d'exécution, vous pouvez créer un fil de discussion dans onCreate(), commencez à l'exécuter dans onStart(), et arrêtez-le dans onStop(). Envisagez également d'utiliser des pools de threads et des exécuteurs à partir du package java.util.concurrent ou les coroutines Kotlin, Thread. Consultez le Exécution de threads sur Android pour en savoir plus déplacer l'exécution vers des threads en arrière-plan.

N'oubliez pas que si vous utilisez un service, il s'exécute toujours dans le thread principal de votre application en par défaut. Vous devez donc toujours créer un thread dans le service s'il effectue des tâches intensives des opérations de blocage.

Principes de base

Pour créer un service, vous devez créer une sous-classe de Service ou en utiliser une. de ses sous-classes existantes. Dans votre implémentation, vous devez remplacer certaines méthodes de rappel qui gérer les aspects clés du cycle de vie du service et fournir un mécanisme qui permet aux composants de au service, le cas échéant. Voici les méthodes de rappel les plus importantes remplacement:

onStartCommand()
Le système appelle cette méthode en appelant startService() lorsqu'un autre composant (tel qu'une activité) demande le démarrage du service. Lorsque cette méthode est exécutée, le service est démarré et peut s'exécuter dans en arrière-plan indéfiniment. Si vous mettez en œuvre cela, il est de votre responsabilité d'arrêter le service lorsque son travail est terminé en appelant stopSelf() ou stopService(). Si vous souhaitez uniquement fournir une liaison, vous ne devez pas devez implémenter cette méthode.
onBind()
Le système appelle cette méthode en appelant bindService() lorsqu'un autre composant souhaite se lier au service (pour effectuer un RPC, par exemple). Dans votre implémentation de cette méthode, vous devez fournir une interface que les clients utiliser pour communiquer avec le service en renvoyant un IBinder. Vous devez toujours mettre en œuvre cette méthode ; Toutefois, si vous ne voulez pas autoriser la liaison, vous devez renvoyer "null".
onCreate()
Le système appelle cette méthode pour effectuer des procédures de configuration ponctuelles lorsque le service est créé initialement (avant d'appeler onStartCommand() ou onBind()). Si le service est déjà en cours d'exécution, cette méthode n'est pas appelé.
onDestroy()
Le système appelle cette méthode lorsque le service n'est plus utilisé et est en cours de destruction. Votre service doit implémenter cela pour nettoyer toutes les ressources, telles que les threads, des écouteurs ou des récepteurs. Il s'agit du dernier appel que le service reçoit.

Si un composant démarre le service en appelant startService() (ce qui entraîne un appel à onStartCommand()), le service continue de s'exécuter jusqu'à ce qu'elle s'arrête avec stopSelf() ou une autre l'arrête en appelant stopService().

Si un composant appelle bindService() pour créer le service et que onStartCommand() n'est pas appelé, le service s'exécute tant que le composant y est lié. Une fois le service dissocié de tous ses clients, le système le détruit.

Le système Android n'arrête un service que lorsque la mémoire est faible et qu'il doit récupérer le système pour l'activité axée sur l'utilisateur. Si le service est lié à une activité dont le rôle concentré, il est moins susceptible de semer la mort ; si le service est déclaré pour s'exécuter au premier plan, il est rarement arrêté. Si le service est en cours d'exécution et que son exécution est longue, le système baisse sa position dans la liste des tâches en arrière-plan au fil du temps, et le service devient très sensible arrêt : si votre service est démarré, vous devez le concevoir pour gérer correctement les redémarrages. par le système. Si le système arrête votre service, il le redémarre dès que des ressources disponible, mais cela dépend également de la valeur renvoyée par onStartCommand(). Pour en savoir plus, pour savoir quand le système peut détruire un service, consultez la page Processus et exécutions de threads document.

Dans les sections suivantes, vous verrez comment créer startService() et bindService() et leur utilisation. à partir d'autres composants d'application.

Déclarer un service dans le fichier manifeste

Vous devez déclarer tous les services dans le fichier manifeste, tout comme pour les activités et les autres composants.

Pour déclarer votre service, ajoutez un élément <service> en tant qu'enfant du <application> ; . Voici un exemple :

<manifest ... >
  ...
  <application ... >
      <service android:name=".ExampleService" />
      ...
  </application>
</manifest>

Voir l'élément <service> pour en savoir plus sur la déclaration de votre service dans le fichier manifeste.

Vous pouvez inclure d'autres attributs dans l'élément <service> pour définir des propriétés telles que les autorisations requises pour démarrer le service et le processus que le service doit exécuter. android:name est le seul attribut obligatoire : il spécifie le nom de classe du service. Après vous publiez votre application, ne modifiez pas son nom pour éviter toute interruption du code, car il dépend d'intents explicites pour démarrer ou lier le service (consultez l'article de blog Things Cela ne peut pas être modifié).

Attention: Pour vous assurer que votre application est sécurisée, utilisez toujours un intent explicite lors du démarrage d'une Service et ne déclarez pas de filtres d'intent pour vos services. L'utilisation d'un intent implicite pour démarrer un service représente un risque de sécurité, car vous ne pouvez pas être certain du service qui répond à l'intent, et l'utilisateur ne peut pas voir quel service démarre. À partir d'Android 5.0 (niveau d'API 21), le système génère une exception si vous appelez bindService() avec un intent implicite.

Pour vous assurer que votre service n'est disponible que pour votre application, procédez comme suit : y compris android:exported et en le définissant sur false. Cela empêche les autres applications de démarrer votre même en utilisant un intent explicite.

Remarque: Les utilisateurs peuvent voir les services en cours d'exécution sur leur appareil. S'ils voient un service qu’ils ne reconnaissent pas ou ne font pas confiance, ils peuvent arrêter le service. Dans pour éviter que votre service ne soit arrêté accidentellement par les utilisateurs, vous devez pour ajouter android:description à la variable <service> dans le fichier manifeste de votre application. Dans la description, Fournissez une courte phrase expliquant la fonction du service et ses avantages qu'il fournit.

Créer un service démarré

Un service démarré est un service qu'un autre composant commence par appeler startService(), ce qui entraîne un appel au service onStartCommand().

Lorsqu'un service est démarré, son cycle de vie est indépendant du qui l'a lancée. Le service peut s'exécuter en arrière-plan indéfiniment, même si le composant qui l'a démarré est détruit. Le service doit donc s'arrêter est terminée en appelant stopSelf(), ou un autre composant peut l'arrêter en appelant stopService().

Un composant d'application, tel qu'une activité, peut démarrer le service en appelant startService() et en transmettant un Intent. spécifiant le service et incluant toutes les données que le service doit utiliser. Le service reçoit cette Intent dans la méthode onStartCommand().

Par exemple, supposons qu'une activité doive enregistrer des données dans une base de données en ligne. L'activité peut démarrer un service associé et lui fournir les données à économiser en transmettant un intent à startService(). Le service reçoit l'intent dans onStartCommand(), se connecte à Internet et effectue l'action transaction de base de données. Une fois la transaction terminée, le service s'arrête et détruit.

Attention:Un service s'exécute dans le même processus que l'application. où elles sont déclarées et dans le thread principal de cette application par défaut. Si votre service effectue des opérations intensives ou bloquantes pendant que l'utilisateur interagit avec une activité du même application, le service ralentit les performances de l'activité. Pour éviter toute incidence sur l'application des performances, démarrez un nouveau thread dans le service.

La classe Service est la classe de base pour tous les services. Lorsque vous étendez cette classe, il est important de créer un nouveau fil de discussion dans lequel le service peut terminer tout son travail ; le service utilise le thread principal de votre application par défaut, ce qui peut ralentir les performances de toute activité exécutée par votre application.

Le framework Android fournit également le IntentService sous-classe de Service qui utilise un thread de travail pour gérer toutes les requêtes de démarrage, une par une. L'utilisation de cette classe n'est pas recommandé pour les nouvelles applications. En effet, elle ne fonctionnera pas correctement à partir d'Android 8 Oreo, en raison de la Introduction des limites d'exécution en arrière-plan. De plus, elle sera obsolète à partir d'Android 11. Vous pouvez utiliser JobIntentService Remplacement de IntentService, compatible avec les versions plus récentes d'Android.

Les sections suivantes décrivent comment implémenter votre propre service personnalisé, mais vous devez envisagez plutôt d'utiliser WorkManager pour la plupart des cas d'utilisation. Consultez le guide du traitement en arrière-plan sur Android. pour voir s'il existe une solution adaptée à vos besoins.

Étendre la classe Service

Vous pouvez étendre la classe Service. pour gérer chaque intent entrant. Voici à quoi pourrait ressembler une implémentation de base:

Kotlin

class HelloService : Service() {

    private var serviceLooper: Looper? = null
    private var serviceHandler: ServiceHandler? = null

    // Handler that receives messages from the thread
    private inner class ServiceHandler(looper: Looper) : Handler(looper) {

        override fun handleMessage(msg: Message) {
            // Normally we would do some work here, like download a file.
            // For our sample, we just sleep for 5 seconds.
            try {
                Thread.sleep(5000)
            } catch (e: InterruptedException) {
                // Restore interrupt status.
                Thread.currentThread().interrupt()
            }

            // Stop the service using the startId, so that we don't stop
            // the service in the middle of handling another job
            stopSelf(msg.arg1)
        }
    }

    override fun onCreate() {
        // Start up the thread running the service.  Note that we create a
        // separate thread because the service normally runs in the process's
        // main thread, which we don't want to block.  We also make it
        // background priority so CPU-intensive work will not disrupt our UI.
        HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND).apply {
            start()

            // Get the HandlerThread's Looper and use it for our Handler
            serviceLooper = looper
            serviceHandler = ServiceHandler(looper)
        }
    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show()

        // For each start request, send a message to start a job and deliver the
        // start ID so we know which request we're stopping when we finish the job
        serviceHandler?.obtainMessage()?.also { msg ->
            msg.arg1 = startId
            serviceHandler?.sendMessage(msg)
        }

        // If we get killed, after returning from here, restart
        return START_STICKY
    }

    override fun onBind(intent: Intent): IBinder? {
        // We don't provide binding, so return null
        return null
    }

    override fun onDestroy() {
        Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show()
    }
}

Java

public class HelloService extends Service {
  private Looper serviceLooper;
  private ServiceHandler serviceHandler;

  // Handler that receives messages from the thread
  private final class ServiceHandler extends Handler {
      public ServiceHandler(Looper looper) {
          super(looper);
      }
      @Override
      public void handleMessage(Message msg) {
          // Normally we would do some work here, like download a file.
          // For our sample, we just sleep for 5 seconds.
          try {
              Thread.sleep(5000);
          } catch (InterruptedException e) {
              // Restore interrupt status.
              Thread.currentThread().interrupt();
          }
          // Stop the service using the startId, so that we don't stop
          // the service in the middle of handling another job
          stopSelf(msg.arg1);
      }
  }

  @Override
  public void onCreate() {
    // Start up the thread running the service. Note that we create a
    // separate thread because the service normally runs in the process's
    // main thread, which we don't want to block. We also make it
    // background priority so CPU-intensive work doesn't disrupt our UI.
    HandlerThread thread = new HandlerThread("ServiceStartArguments",
            Process.THREAD_PRIORITY_BACKGROUND);
    thread.start();

    // Get the HandlerThread's Looper and use it for our Handler
    serviceLooper = thread.getLooper();
    serviceHandler = new ServiceHandler(serviceLooper);
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
      Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();

      // For each start request, send a message to start a job and deliver the
      // start ID so we know which request we're stopping when we finish the job
      Message msg = serviceHandler.obtainMessage();
      msg.arg1 = startId;
      serviceHandler.sendMessage(msg);

      // If we get killed, after returning from here, restart
      return START_STICKY;
  }

  @Override
  public IBinder onBind(Intent intent) {
      // We don't provide binding, so return null
      return null;
  }

  @Override
  public void onDestroy() {
    Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
  }
}

L'exemple de code gère tous les appels entrants dans onStartCommand() et publie la tâche dans un Handler exécuté sur un thread d'arrière-plan. Il fonctionne comme un IntentService et traite toutes les requêtes les unes après les autres. Vous pouvez modifier le code pour exécuter la tâche sur un pool de threads, par exemple si vous souhaitez exécuter plusieurs requêtes simultanément.

Notez que la méthode onStartCommand() doit renvoyer une entier. Le nombre entier est une valeur qui décrit la façon dont le système doit poursuivre le service que le système le tue. La valeur renvoyée de onStartCommand() doit correspondre à l'un des éléments suivants : constantes:

START_NOT_STICKY
Si le système supprime le service après le retour de onStartCommand(), ne recréez pas le service, sauf s'il existe les intents à livrer. Il s'agit de l'option la plus sûre pour éviter d'exécuter votre service lorsque cela n'est pas nécessaire et quand votre application peut simplement redémarrer les tâches inachevées.
START_STICKY
Si le système arrête le service après le retour de onStartCommand(), recréez le service et appelez onStartCommand(), mais ne renvoyez pas le dernier intent. À la place, le système appelle onStartCommand() avec un un intent nul, sauf s'il existe des intents en attente pour démarrer le service. Dans ce cas, ces intents sont fournis. Ceci est adapté aux lecteurs multimédias (ou services similaires) qui ne sont pas des commandes en cours d'exécution, mais qui s'exécutent indéfiniment et attendent un job.
START_REDELIVER_INTENT
Si le système supprime le service après le retour de onStartCommand(), recréez-le et appelez onStartCommand() avec le dernier intent transmis au Google Cloud. Tous les intents en attente sont transmis l'un après l'autre. Cela convient aux services l'exécution active d'une tâche qui doit reprendre immédiatement, telle que le téléchargement d'un fichier.

Pour en savoir plus sur ces valeurs renvoyées, consultez la documentation de référence pour chaque constante.

Démarrer un service

Vous pouvez démarrer un service à partir d'une activité ou d'un autre composant d'application en transmettant un Intent à startService() ou startForegroundService(). La Le système Android appelle la méthode onStartCommand() du service et lui transmet Intent, qui spécifie le service à démarrer.

Remarque: Si votre application cible le niveau d'API 26 ou supérieur, le système impose des restrictions sur l'utilisation ou la création des services d'arrière-plan, sauf si l'application se trouve au premier plan. Si une appli doit créer un service de premier plan, l'application doit appeler startForegroundService(). Cette méthode crée un service d'arrière-plan, mais indique au système que le service va être promu au premier plan. Une fois le service créé, il doit appeler sa méthode startForeground() dans pendant cinq secondes.

Par exemple, une activité peut démarrer l'exemple de service de la section précédente (HelloService) à l'aide d'un intent explicite avec startService(), comme indiqué ci-dessous:

Kotlin

startService(Intent(this, HelloService::class.java))

Java

startService(new Intent(this, HelloService.class));

La méthode startService() renvoie immédiatement un résultat. le système Android appelle la méthode onStartCommand() du service. Si le service n'est pas déjà en cours d'exécution, le système appelle d'abord onCreate(), puis il appelle onStartCommand()

Si le service ne fournit pas également de liaison, l'intent fourni avec startService() est le seul mode de communication entre le composant d'application et le service. Cependant, si vous souhaitez que le service renvoie un résultat, le client qui démarre le service peut créer un PendingIntent pour une diffusion. (avec getBroadcast()) et le livrer au service dans le Intent qui démarre le service. Le service peut alors utiliser diffuser pour fournir un résultat.

Plusieurs requêtes de démarrage du service entraînent plusieurs appels correspondants aux appels du service onStartCommand() Cependant, une seule demande d'arrêt le service (avec stopSelf() ou stopService()) est requis pour l'arrêter.

Arrêter un service

Un service démarré doit gérer son propre cycle de vie. Autrement dit, le système ne s'arrête pas ou détruire le service, sauf s'il doit récupérer la mémoire système et le service continue de s'exécuter après le retour de onStartCommand(). La service doit s'arrêter en appelant stopSelf() ou un autre peut l'arrêter en appelant stopService().

Une fois que vous avez demandé l'arrêt avec stopSelf() ou stopService(), le système détruit le service possible.

Si votre service traite plusieurs requêtes simultanément vers onStartCommand(), vous ne devez pas arrêter lorsque vous avez terminé de traiter une requête de démarrage, car vous avez peut-être reçu une nouvelle start request (l'arrêt à la fin de la première requête met fin à la seconde). Pour éviter ce problème, vous pouvez utiliser stopSelf(int) pour vous assurer que votre demande à le service est toujours basé sur la requête de démarrage la plus récente. Autrement dit, lorsque vous appelez stopSelf(int), vous transmettez l'ID de la requête de démarrage (startId envoyé à onStartCommand()) auquel votre demande d'interruption de service correspond. Ensuite, si le service reçoit une nouvelle requête de démarrage avant que vous ne puissiez appeler stopSelf(int), l'ID ne correspond pas et le service ne s'arrête pas.

Attention:Pour éviter de gaspiller des ressources système et de consommer de la batterie, assurez-vous que votre application arrête ses services une fois qu'elle a fini de fonctionner. Si nécessaire, d'autres composants peuvent arrêter le service en appelant stopService(). Même si vous activez la liaison pour le service, vous devez toujours arrêter le service vous-même s'il reçoit un appel vers onStartCommand().

Pour en savoir plus sur le cycle de vie d'un service, consultez la section ci-dessous sur la gestion du cycle de vie d'un service.

Créer un service lié

Un service lié est un service qui permet aux composants d'application de s'associer à celui-ci en appelant bindService() pour créer une connexion à long terme. Il n'autorise généralement pas les composants à le démarrer en appelant startService().

Créer un service lié lorsque vous souhaitez interagir avec celui-ci à partir d'activités et d'autres composants de votre application, ou pour exposer certaines fonctionnalités de votre application d'autres applications via la communication inter-processus (IPC).

Pour créer un service lié, implémentez la méthode de rappel onBind() afin de renvoyer un IBinder qui définit l'interface de communication avec le service. D'autres composants d'application peuvent ensuite appeler bindService() pour récupérer l'interface et commencer à appeler des méthodes sur le service. Le service ne réside que pour diffuser le composant d'application est lié au service. Par conséquent, lorsqu'aucun composant n'est lié au service, le système le détruit. Vous n'avez pas besoin d'arrêter un service lié comme vous le feriez lorsque le service a commencé jusqu'au onStartCommand().

Pour créer un service lié, vous devez définir l'interface qui indique comment un client peut communiquer avec le service. Cette interface entre le service et un client doit être une implémentation de IBinder. C'est ce que votre service doit faire renvoyé par la méthode de rappel onBind(). Une fois que le client a reçu l'IBinder, il peut commencer interagissant avec le service via cette interface.

Plusieurs clients peuvent s'associer au service simultanément. Lorsqu'un client a fini d'interagir avec le service, il appelle unbindService() pour annuler la liaison. Si aucun client n'est lié au service, le système le détruit.

Il existe plusieurs façons d'implémenter un service lié, plus compliqué qu'un service en cours de démarrage. C'est pourquoi la discussion sur le service lié apparaît dans un document distinct sur les services liés.

Envoyer des notifications à l'utilisateur

Lorsqu'un service est en cours d'exécution, il peut informer l'utilisateur d'événements à l'aide de notifications snackbar ou de notifications dans la barre d'état.

Une notification de snackbar est un message qui apparaît à la surface de la fenêtre actuelle pour une quelques instants avant de disparaître. Une notification de barre d'état contient une icône dans la barre d'état avec une que l'utilisateur peut sélectionner pour effectuer une action (par exemple, lancer une activité).

En général, une notification dans la barre d'état est la meilleure technique à utiliser lorsque des tâches en arrière-plan le téléchargement d’un fichier est terminé et l’utilisateur peut maintenant agir dessus. Lorsque l'utilisateur sélectionne la notification dans la vue développée, la notification peut lancer une activité (pour afficher le fichier téléchargé, par exemple).

Gérer le cycle de vie d'un service

Le cycle de vie d'un service est beaucoup plus simple que celui d'une activité. Cependant, il est encore plus il est important de porter une attention particulière à la façon dont votre service est créé et détruit, service peut s'exécuter en arrière-plan à l'insu de l'utilisateur.

Le cycle de vie d'un service, de sa création à sa destruction, peut suivre l'un des deux chemins suivants:

  • Un service démarré

    Le service est créé lorsqu'un autre composant appelle startService(). Le service fonctionne ensuite indéfiniment et doit s'arrêter en appelant stopSelf(). Un autre composant peut également arrêter service en appelant stopService(). Lorsque le service est arrêté, le système le détruit.

  • Un service lié

    Le service est créé lorsqu'un autre composant (un client) appelle bindService(). Le client communique ensuite avec le service via une interface IBinder. Le client peut fermer la connexion en appelant unbindService() Plusieurs clients peuvent être liés à le même service et lorsqu'ils sont tous dissociés, le système le détruit. Le service n'a pas besoin de s'arrêter automatiquement.

Ces deux chemins ne sont pas entièrement distincts. Vous pouvez lier à un service qui est déjà a commencé par startService(). Par exemple, vous pouvez démarrer un service de musique de fond en appelant startService() avec un Intent qui identifie la musique à lire. Plus tard, Par exemple, lorsque l'utilisateur souhaite exercer un certain contrôle sur le lecteur ou obtenir des informations titre actuel, une activité peut s'associer au service en appelant bindService(). Dans ce cas, stopService() ou stopSelf() n'arrête pas réellement le service jusqu'à ce que tous les clients soient dissociés.

Implémenter les rappels de cycle de vie

Comme une activité, un service possède des méthodes de rappel de cycle de vie que vous pouvez implémenter pour surveiller les changements d'état du service et effectuer le travail aux moments appropriés. Le squelette suivant illustre chacune des méthodes du cycle de vie:

Kotlin

class ExampleService : Service() {
    private var startMode: Int = 0             // indicates how to behave if the service is killed
    private var binder: IBinder? = null        // interface for clients that bind
    private var allowRebind: Boolean = false   // indicates whether onRebind should be used

    override fun onCreate() {
        // The service is being created
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // The service is starting, due to a call to startService()
        return startMode
    }

    override fun onBind(intent: Intent): IBinder? {
        // A client is binding to the service with bindService()
        return binder
    }

    override fun onUnbind(intent: Intent): Boolean {
        // All clients have unbound with unbindService()
        return allowRebind
    }

    override fun onRebind(intent: Intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }

    override fun onDestroy() {
        // The service is no longer used and is being destroyed
    }
}

Java

public class ExampleService extends Service {
    int startMode;       // indicates how to behave if the service is killed
    IBinder binder;      // interface for clients that bind
    boolean allowRebind; // indicates whether onRebind should be used

    @Override
    public void onCreate() {
        // The service is being created
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // The service is starting, due to a call to startService()
        return startMode;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // A client is binding to the service with bindService()
        return binder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        // All clients have unbound with unbindService()
        return allowRebind;
    }
    @Override
    public void onRebind(Intent intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }
    @Override
    public void onDestroy() {
        // The service is no longer used and is being destroyed
    }
}

Remarque:Contrairement aux méthodes de rappel du cycle de vie d'une activité, ne sont pas nécessaires pour appeler l'implémentation de la super-classe de ces méthodes de rappel.

Figure 2. Cycle de vie du service Le diagramme de gauche montre le cycle de vie lorsque le service est créé avec startService(). Le schéma de droite le montre lors de la création du service. avec bindService().

La figure 2 illustre les méthodes de rappel types pour un service. Bien que la figure sépare services créés par startService() à partir de ces créé par bindService(), conserver à l'esprit que n'importe quel service, quelle que soit la façon dont il a été démarré, peut potentiellement permettre aux clients de s'y lier. Un service initialement démarré avec onStartCommand() (par un client appelant startService()) peut toujours recevoir un appel à onBind() (lorsqu'un client appelle bindService()).

En mettant en œuvre ces méthodes, vous pouvez surveiller ces deux boucles imbriquées du réseau cycle de vie:

  • La durée de vie complète d'un service se produit entre le moment où onCreate() est appelé et celui où onDestroy() renvoie. Comme une activité, un service effectue sa configuration initiale dans onCreate() et libère toutes les ressources restantes dans onDestroy(). Par exemple, un Le service de lecture de musique peut créer le thread dans lequel la musique est lue dans onCreate(), puis l'arrêter dans onDestroy().

    Remarque: onCreate() et onDestroy() sont appelées pour tous les services, que ce soit elles sont créées par startService() ou bindService().

  • La durée de vie active d'un service commence par un appel à onStartCommand() ou onBind(). Chaque méthode reçoit le Intent qui a été transmis à startService() ou bindService().

    Si le service est démarré, la durée de vie active se termine au moment où se termine (le service est toujours actif même après le retour de onStartCommand()). Si le service est lié, la durée de vie active se termine lorsque onUnbind() est renvoyé.

Remarque:Bien qu'un service démarré soit arrêté par un appel à stopSelf() ou stopService(), il n'y a pas de rappel respectif pour la méthode (il n'y a pas de rappel onStop()). À moins que le service ne soit lié à un client, le système le détruit lorsque le service est arrêté. onDestroy() est le seul rappel reçu.

Pour en savoir plus sur la création d'un service fournissant une liaison, consultez le document Services liés. qui contient davantage d'informations sur les onRebind(). de rappel de la section Gérer le cycle de vie un service lié.