Un Service
est un composant d'application qui peut exécuter 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 à s'exécuter pendant un certain temps, même après que l'utilisateur a changé d'application. De plus, un composant peut se lier à un service pour interagir avec lui et même effectuer une communication interprocessus (IPC). Par exemple, un service peut gérer les 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 processus d'hébergement. Le service ne crée pas son propre thread et ne s'exécute pas dans un processus distinct, sauf si vous le spécifiez. Vous devez exécuter toutes les opérations bloquantes sur un thread distinct dans le service pour éviter les erreurs ANR (Application Not Responding).
Types de services
Voici les trois types de services:
- Premier plan
-
Un service de premier plan effectue une opération visible par l'utilisateur. Par exemple, une application audio utilise un service de premier plan pour lire un titre 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 sachent que le service est en cours d'exécution. Cette notification ne peut pas être ignorée, sauf si le service est arrêté ou supprimé du premier plan.
Découvrez comment configurer les services de premier plan dans votre application.
Remarque:L'API WorkManager offre un moyen flexible de planifier des tâches et peut exécuter ces tâches en tant que services de premier plan si nécessaire. Dans de nombreux cas, il est préférable d'utiliser WorkManager plutôt que de recourir directement aux services de premier plan.
- Arrière-plan
- Un service en arrière-plan effectue une opération que l'utilisateur ne remarque pas directement. Par exemple, si une application utilise un service pour compacter son espace de stockage, il s'agit généralement d'un service en arrière-plan.
Remarque:Si votre application cible le niveau d'API 26 ou une version ultérieure, le système impose des restrictions sur l'exécution des services en arrière-plan lorsque l'application elle-même n'est pas au premier plan. Dans la plupart des cas, par exemple, vous ne devez pas accéder aux informations de localisation en arrière-plan. À la place, planifiez des tâches à l'aide de WorkManager.
- Associée
- Un service est lié lorsqu'un composant d'application s'y lie en appelant
bindService()
. Un service lié offre une interface client-serveur qui permet aux composants d'interagir avec le service, d'envoyer des requêtes, de recevoir des résultats et même de le faire entre les processus avec la communication interprocessus (IPC). Un service lié ne s'exécute que tant qu'un autre composant d'application y est lié. Plusieurs composants peuvent se lier au service à la fois, mais lorsqu'ils se dissocient tous, 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 s'exécuter indéfiniment) et également permettre la liaison. Il vous suffit d'implémenter quelques méthodes de rappel: onStartCommand()
pour permettre aux composants de le démarrer et onBind()
pour autoriser la liaison.
Que votre service soit démarré, associé ou les deux, n'importe quel composant d'application peut l'utiliser (même à partir d'une application distincte) de la même manière que n'importe quel composant peut utiliser une activité, en le démarrant avec un Intent
. Toutefois, vous pouvez déclarer le service comme privé dans le fichier manifeste et bloquer l'accès des 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 n'interagit pas avec votre application. Vous ne devez donc créer un service que si vous en avez besoin.
Si vous devez effectuer des tâches en dehors de votre thread principal, mais uniquement lorsque l'utilisateur interagit avec votre application, vous devez plutôt créer un thread dans le contexte d'un autre composant de l'application. Par exemple, si vous souhaitez lire de la musique, mais uniquement lorsque votre activité est en cours d'exécution, vous pouvez créer un thread dans onCreate()
, commencer à l'exécuter dans onStart()
et l'arrêter dans onStop()
.
Pensez également à utiliser des pools de threads et des exécuteurs du package java.util.concurrent
ou des coroutines Kotlin au lieu de la classe Thread
traditionnelle. Pour en savoir plus sur le transfert de l'exécution vers des threads en arrière-plan, consultez le document Threading on Android (Exécution de threads sur Android).
N'oubliez pas que si vous utilisez un service, il s'exécute toujours dans le thread principal de votre application par défaut. Vous devez donc créer un thread dans le service s'il effectue des opérations intensives ou bloquantes.
Principes de base
Pour créer un service, vous devez créer une sous-classe de Service
ou utiliser l'une de ses sous-classes existantes. Dans votre implémentation, vous devez remplacer certaines méthodes de rappel qui gèrent les aspects clés du cycle de vie du service et fournir un mécanisme permettant aux composants de se lier au service, le cas échéant. Voici les méthodes de rappel les plus importantes que vous devez remplacer:
onStartCommand()
- Le système appelle cette méthode en appelant
startService()
lorsqu'un autre composant (comme une activité) demande le démarrage du service. Lorsque cette méthode s'exécute, le service est démarré et peut s'exécuter en arrière-plan indéfiniment. Si vous implémentez cette approche, il vous incombe d'arrêter le service une fois son travail terminé en appelantstopSelf()
oustopService()
. Si vous souhaitez uniquement fournir une liaison, vous n'avez pas besoin d'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 (par exemple, pour effectuer un RPC). Dans l'implémentation de cette méthode, vous devez fournir une interface que les clients utilisent pour communiquer avec le service en renvoyant unIBinder
. Vous devez toujours implémenter cette méthode. Toutefois, si vous ne souhaitez pas autoriser la liaison, vous devez renvoyer la valeur 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()
ouonBind()
). Si le service est déjà en cours d'exécution, cette méthode n'est pas appelée. onDestroy()
- Le système appelle cette méthode lorsque le service n'est plus utilisé et est détruit. Votre service doit implémenter cette méthode pour nettoyer toutes les ressources telles que les threads, les écouteurs enregistrés ou les 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'il s'arrête avec stopSelf()
ou qu'un autre composant 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 ne s'exécute que 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 les ressources système pour l'activité qui est au premier plan. Si le service est lié à une activité qui est en focus utilisateur, il est moins susceptible d'être arrêté. Si le service est déclaré s'exécuter au premier plan, il est rarement arrêté.
Si le service est démarré et de longue durée, le système réduit sa position dans la liste des tâches en arrière-plan au fil du temps, et le service devient très susceptible d'être arrêté. Si votre service est démarré, vous devez le concevoir pour qu'il gère correctement les redémarrages du système. Si le système arrête votre service, il le redémarre dès que les ressources sont disponibles, mais cela dépend également de la valeur que vous renvoyez à partir de onStartCommand()
. Pour en savoir plus sur les cas où le système peut détruire un service, consultez la documentation Processes and Threading (Processus et threads).
Dans les sections suivantes, vous découvrirez comment créer les méthodes de service startService()
et bindService()
, ainsi que comment les utiliser à 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 de votre application, comme vous le faites pour les activités et les autres composants.
Pour déclarer votre service, ajoutez un élément <service>
en tant qu'enfant de l'élément <application>
. Voici un exemple :
<manifest ... > ... <application ... > <service android:name=".ExampleService" /> ... </application> </manifest>
Pour en savoir plus sur la déclaration de votre service dans le fichier manifeste, consultez la référence de l'élément <service>
.
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 dans lequel le service doit s'exécuter. L'attribut android:name
est le seul attribut obligatoire. Il spécifie le nom de classe du service. Une fois votre application publiée, laissez ce nom inchangé pour éviter le risque de casser le code en raison de la dépendance à des intents explicites pour démarrer ou lier le service (consultez l'article de blog Éléments qui ne peuvent pas changer).
Attention: Pour vous assurer que votre application est sécurisée, utilisez toujours un intent explicite lorsque vous démarrez un 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 savoir avec certitude quel service répondra à 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.
Vous pouvez vous assurer que votre service n'est disponible que pour votre application en incluant l'attribut android:exported
et en le définissant sur false
. Cela empêche efficacement les autres applications de démarrer votre service, même si elles utilisent un intent explicite.
Remarque : Les utilisateurs peuvent voir les services exécutés sur leur appareil. S'il voit un service qu'il ne reconnaît pas ou auquel il ne fait pas confiance, il peut l'arrêter. Pour éviter que votre service ne soit arrêté accidentellement par les utilisateurs, vous devez ajouter l'attribut android:description
à l'élément <service>
dans le fichier manifeste de votre application. Dans la description, fournissez une courte phrase expliquant le fonctionnement du service et ses avantages.
Créer un service démarré
Un service démarré est un service démarré par un autre composant en appelant startService()
, ce qui entraîne un appel à la méthode onStartCommand()
du service.
Lorsqu'un service est démarré, son cycle de vie est indépendant du composant qui l'a démarré. Le service peut s'exécuter en arrière-plan indéfiniment, même si le composant qui l'a lancé est détruit. Par conséquent, le service doit s'arrêter lorsque sa tâche 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
qui spécifie le service et inclut toutes les données à utiliser par le service. Le service reçoit ce Intent
dans la méthode onStartCommand()
.
Par exemple, supposons qu'une activité doit enregistrer des données dans une base de données en ligne. L'activité peut démarrer un service associé et lui transmettre les données à enregistrer en transmettant un intent à startService()
. Le service reçoit l'intent dans onStartCommand()
, se connecte à Internet et effectue la transaction de base de données. Une fois la transaction terminée, le service s'arrête et est détruit.
Attention:Un service s'exécute dans le même processus que l'application dans laquelle il est déclaré 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é de la même application, le service ralentit les performances de l'activité. Pour éviter d'affecter les performances de l'application, démarrez un nouveau thread dans le service.
La classe Service
est la classe de base de tous les services. Lorsque vous étendez cette classe, il est important de créer un thread dans lequel le service peut effectuer l'ensemble de son travail. Par défaut, le service utilise le thread principal de votre application, ce qui peut ralentir les performances de toute activité exécutée par votre application.
Le framework Android fournit également la sous-classe IntentService
de Service
qui utilise un thread de travail pour gérer toutes les requêtes de démarrage, une à la fois. L'utilisation de cette classe n'est pas recommandée pour les nouvelles applications, car elle ne fonctionnera pas correctement à partir d'Android 8 Oreo, en raison de l'introduction des limites d'exécution en arrière-plan.
De plus, elle est obsolète à partir d'Android 11.
Vous pouvez utiliser JobIntentService comme remplacement de IntentService
, qui est compatible avec les versions plus récentes d'Android.
Les sections suivantes expliquent comment implémenter votre propre service personnalisé. Toutefois, nous vous recommandons vivement d'utiliser WorkManager pour la plupart des cas d'utilisation. Consultez le guide du traitement en arrière-plan sur Android pour déterminer 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 peut 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 le travail sur un Handler
exécuté sur un thread en arrière-plan. Il fonctionne comme un IntentService
et traite toutes les requêtes de manière séquentielle, l'une après l'autre.
Vous pouvez modifier le code pour exécuter le travail 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 un entier. L'entier est une valeur qui décrit comment le système doit poursuivre le service si le système l'arrête. La valeur renvoyée par onStartCommand()
doit être l'une des constantes suivantes:
START_NOT_STICKY
- Si le système arrête le service après le retour de
onStartCommand()
, ne le recréez pas, sauf s'il existe des intents en attente à transmettre. Il s'agit de l'option la plus sûre pour éviter d'exécuter votre service lorsqu'il n'est pas nécessaire et lorsque 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 appelezonStartCommand()
, mais ne renvoyez pas le dernier intent. Au lieu de cela, le système appelleonStartCommand()
avec un intent nul, sauf s'il existe des intents en attente pour démarrer le service. Dans ce cas, ces intents sont envoyés. Cette option convient aux lecteurs multimédias (ou services similaires) qui n'exécutent pas de commandes, mais qui s'exécutent indéfiniment et attendent une tâche. START_REDELIVER_INTENT
- Si le système arrête le service après le retour de
onStartCommand()
, recréez le service et appelezonStartCommand()
avec le dernier intent envoyé au service. Les intents en attente sont transmis à leur tour. Cette option convient aux services qui effectuent activement une tâche qui doit être immédiatement reprise, comme le téléchargement d'un fichier.
Pour en savoir plus sur ces valeurs de retour, consultez la documentation de référence associée 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()
. Le système Android appelle la méthode onStartCommand()
du service et lui transmet le Intent
, qui spécifie le service à démarrer.
Remarque: Si votre application cible le niveau d'API 26 ou une version ultérieure, le système impose des restrictions sur l'utilisation ou la création de services en arrière-plan, sauf si l'application elle-même est au premier plan. Si une application doit créer un service de premier plan, elle doit appeler startForegroundService()
. Cette méthode crée un service en arrière-plan, mais elle indique au système que le service s'affichera au premier plan. Une fois le service créé, il doit appeler sa méthode startForeground()
dans les 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 illustré ci-dessous:
Kotlin
startService(Intent(this, HelloService::class.java))
Java
startService(new Intent(this, HelloService.class));
La méthode startService()
renvoie immédiatement, et 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 onStartCommand()
.
Si le service ne fournit pas également de liaison, l'intent envoyé avec startService()
est le seul mode de communication entre le composant de l'application et le service. Toutefois, 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 transmettre au service dans le Intent
qui démarre le service. Le service peut ensuite utiliser la diffusion pour générer un résultat.
Plusieurs requêtes de démarrage du service entraînent plusieurs appels correspondants à l'onStartCommand()
du service. Toutefois, une seule requête pour arrêter le service (avec stopSelf()
ou stopService()
) est nécessaire.
Arrêter un service
Un service démarré doit gérer son propre cycle de vie. Autrement dit, le système n'arrête ni ne détruit 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()
. Le service doit s'arrêter en appelant stopSelf()
, ou un autre composant peut l'arrêter en appelant stopService()
.
Une fois la demande d'arrêt envoyée avec stopSelf()
ou stopService()
, le système détruit le service dès que possible.
Si votre service gère plusieurs requêtes à onStartCommand()
simultanément, vous ne devez pas arrêter le service lorsque vous avez terminé de traiter une requête de démarrage, car vous avez peut-être reçu une nouvelle requête de démarrage (l'arrêt à la fin de la première requête mettrait fin à la seconde). Pour éviter ce problème, vous pouvez utiliser stopSelf(int)
pour vous assurer que votre requête d'arrêt du service est toujours basée 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 (le startId
envoyé à onStartCommand()
) auquel votre requête d'arrêt 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 l'énergie de la batterie, assurez-vous que votre application arrête ses services lorsqu'elle a terminé.
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 à 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é permet aux composants d'application de s'y associer en appelant bindService()
pour créer une connexion de longue durée.
En règle générale, il n'autorise pas les composants à démarrer en appelant startService()
.
Créez un service lié lorsque vous souhaitez interagir avec le service à partir d'activités et d'autres composants de votre application, ou pour exposer certaines des fonctionnalités de votre application à d'autres applications via la communication interprocessus (IPC).
Pour créer un service lié, implémentez la méthode de rappel onBind()
pour renvoyer un IBinder
qui définit l'interface de communication avec le service. Les autres composants de l'application peuvent ensuite appeler bindService()
pour récupérer l'interface et commencer à appeler des méthodes sur le service. Le service ne sert qu'à servir le composant d'application qui lui est associé. Par conséquent, lorsque le système ne trouve aucun composant lié au service, il le détruit.
Vous n'avez pas besoin d'arrêter un service lié de la même manière que lorsque le service est démarré via onStartCommand()
.
Pour créer un service lié, vous devez définir l'interface qui spécifie comment un client peut communiquer avec le service. Cette interface entre le service et un client doit être une implémentation de IBinder
et c'est ce que votre service doit renvoyer à partir de la méthode de rappel onBind()
. Une fois que le client a reçu le IBinder
, il peut commencer à interagir avec le service via cette interface.
Plusieurs clients peuvent s'associer au service simultanément. Lorsqu'un client a terminé d'interagir avec le service, il appelle unbindService()
pour se dissocier.
Lorsque le service n'est lié à aucun client, le système le détruit.
Il existe plusieurs façons d'implémenter un service lié, et l'implémentation est plus complexe qu'un service démarré. Pour ces raisons, la discussion sur les services liés 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 des événements à l'aide de notifications de barre d'alerte ou de notifications de barre d'état.
Une notification de barre de notification est un message qui n'apparaît que pendant un court instant sur la surface de la fenêtre actuelle avant de disparaître. Une notification de barre d'état affiche une icône dans la barre d'état avec un message, que l'utilisateur peut sélectionner pour effectuer une action (comme démarrer une activité).
En règle générale, une notification de barre d'état est la meilleure technique à utiliser lorsqu'une tâche en arrière-plan, telle qu'un téléchargement de fichier, est terminée et que l'utilisateur peut désormais y répondre. Lorsque l'utilisateur sélectionne la notification dans la vue développée, elle peut démarrer une activité (par exemple, pour afficher le fichier téléchargé).
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é. Toutefois, il est encore plus important de prêter une attention particulière à la façon dont votre service est créé et détruit, car un service peut s'exécuter en arrière-plan sans que l'utilisateur en soit informé.
Le cycle de vie du 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 s'exécute ensuite indéfiniment et doit s'arrêter en appelantstopSelf()
. Un autre composant peut également arrêter le service en appelantstopService()
. 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 interfaceIBinder
. Le client peut fermer la connexion en appelantunbindService()
. Plusieurs clients peuvent se lier au même service. Lorsque tous ces clients se dissocient, le système détruit le service. Le service n'a pas besoin de s'arrêter.
Ces deux chemins ne sont pas entièrement distincts. Vous pouvez vous associer à un service déjà démarré avec startService()
. Par exemple, vous pouvez démarrer un service de musique en arrière-plan en appelant startService()
avec un Intent
qui identifie la musique à lire. Plus tard, éventuellement lorsque l'utilisateur souhaite contrôler le lecteur ou obtenir des informations sur le titre en cours, une activité peut se lier au service en appelant bindService()
. Dans ce cas, stopService()
ou stopSelf()
n'arrête pas réellement le service tant que tous les clients ne se sont pas dissociés.
Implémenter les rappels de cycle de vie
Comme une activité, un service dispose de méthodes de rappel de cycle de vie que vous pouvez implémenter pour surveiller les modifications de l'état du service et effectuer des tâches au moment opportun. Le service squelette suivant illustre chacune des méthodes de 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 funonCreate
() { // The service is being created } override funonStartCommand
(intent: Intent?, flags: Int, startId: Int): Int { // The service is starting, due to a call to startService() return startMode } override funonBind
(intent: Intent): IBinder? { // A client is binding to the service with bindService() return binder } override funonUnbind
(intent: Intent): Boolean { // All clients have unbound with unbindService() return allowRebind } override funonRebind
(intent: Intent) { // A client is binding to the service with bindService(), // after onUnbind() has already been called } override funonDestroy
() { // 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 voidonCreate
() { // The service is being created } @Override public intonStartCommand
(Intent intent, int flags, int startId) { // The service is starting, due to a call tostartService()
return startMode; } @Override public IBinderonBind
(Intent intent) { // A client is binding to the service withbindService()
return binder; } @Override public booleanonUnbind
(Intent intent) { // All clients have unbound withunbindService()
return allowRebind; } @Override public voidonRebind
(Intent intent) { // A client is binding to the service withbindService()
, // after onUnbind() has already been called } @Override public voidonDestroy
() { // The service is no longer used and is being destroyed } }
Remarque:Contrairement aux méthodes de rappel du cycle de vie de l'activité, vous n'êtes pas tenu d'appeler l'implémentation de la super-classe de ces méthodes de rappel.
La figure 2 illustre les méthodes de rappel typiques d'un service. Bien que la figure sépare les services créés par startService()
de ceux créés par bindService()
, gardez à l'esprit que tout service, quel que soit son démarrage, peut potentiellement permettre aux clients de s'y associer.
Un service initialement démarré avec onStartCommand()
(par un client appelant startService()
) peut toujours recevoir un appel à onBind()
(lorsqu'un client appelle bindService()
).
En implémentant ces méthodes, vous pouvez surveiller ces deux boucles imbriquées du cycle de vie du service:
- La durée de vie complète d'un service se produit entre le moment où
onCreate()
est appelé et le moment oùonDestroy()
est renvoyé. Comme une activité, un service effectue sa configuration initiale dansonCreate()
et libère toutes les ressources restantes dansonDestroy()
. Par exemple, un service de lecture de musique peut créer le thread dans lequel la musique est lue dansonCreate()
, puis l'arrêter dansonDestroy()
.Remarque: Les méthodes
onCreate()
etonDestroy()
sont appelées pour tous les services, qu'ils soient créés parstartService()
oubindService()
. - La durée de vie active d'un service commence par un appel à
onStartCommand()
ouonBind()
. Chaque méthode reçoit leIntent
transmis àstartService()
oubindService()
.Si le service est démarré, la durée de vie active se termine en même temps que la durée de vie entière (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 lorsqueonUnbind()
est renvoyé.
Remarque:Bien qu'un service démarré soit arrêté par un appel à stopSelf()
ou stopService()
, il n'existe pas de rappel correspondant pour le service (il n'y a pas de rappel onStop()
). Sauf si le service est lié à un client, le système le détruit lorsqu'il est arrêté. onDestroy()
est le seul rappel reçu.
Pour en savoir plus sur la création d'un service qui fournit une liaison, consultez le document Services liés, qui inclut des informations supplémentaires sur la méthode de rappel onRebind()
dans la section Gérer le cycle de vie d'un service lié.