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. Dans un premier temps, un service peut continuer à fonctionner pendant un certain temps, même après que l’utilisateur soit passé à une autre application. En outre, 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 des transactions réseau, jouer de la musique, effectuer des entrées/sorties 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 séparé, sauf indication contraire de votre part. Vous devriez exécuter toute opération de blocage sur un thread séparé dans le service pour éviter les erreurs ApplicationNot Responding (ANR).
- Types de services
- Choisir entre un service et un thread
- Les bases
- Déclarer un service dans le manifeste
- Création d’un service démarré
- Extension de la classe Service
- Kotlin
- Java
- Démarrer un service
- Kotlin
- Java
- Arrêter un service
- Création d’un service lié
- Envoyer des notifications à l’utilisateur
- Gérer le cycle de vie d’un service
- Implémentation des callbacks du cycle de vie
- Kotlin
- Java
Types de services
Voici les trois différents types de services :
Avant-plan
Un service d’avant-plan effectue une certaine opération qui est perceptible par l’utilisateur. Par exemple, une application audio utiliserait un service de premier plan pour lire une piste audio. Les services d’avant-plan doivent afficher une notification. Les services d’avant-plan continuent de fonctionner même lorsque l’utilisateur n’interagit pas avec l’app.
Lorsque vous utilisez un service d’avant-plan, vous devez afficher une notification afin que les utilisateurs soient activement conscients que le service est en cours d’exécution. Cette notification ne peut pas être rejetée à moins que le service ne soit soit arrêté ou retiré du premier plan.
En savoir plus sur la façon de configurer les services de premier plan dans votre app.
Remarque : L’API WorkManager offre une façon flexible de planifier des tâches et est capable d’exécuter ces tâches en tant que services de premier plan si nécessaire. Dans de nombreux cas, l’utilisation de WorkManager est préférable à l’utilisation directe des 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 app utilise un service pour compacter son stockage, ce serait généralement un service d’arrière-plan.
Note : Si votre app vise le niveau 26 de l’API ou plus, le système impose des restrictions sur l’exécution des services d’arrière-plan lorsque l’app elle-même n’est pas au premier plan. Dans la plupart des situations, par exemple, vous ne devriez pas accéder aux informations de localisation depuis l’arrière-plan. Planifiez plutôt les tâches à l’aide de WorkManager.
Lié Un service est lié lorsqu’un composant applicatif se lie à lui en appelantbindService()
. Un service lié offre une interface client-serveur qui permet aux composants d’interagir avec le service, d’envoyer des demandes, de recevoir des résultats, et même de le faire à travers les processus avec la communication interprocessus (IPC). Un service lié ne fonctionne que tant qu’un autre composant d’application lui est lié. Plusieurs composants peuvent se lier au service en même temps, mais lorsque tous se délient, le service est détruit.
Bien que cette documentation aborde généralement les 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 lebinding. Il s’agit simplement de savoir si vous implémentez un couple de méthodes de rappel : onStartCommand()
pour permettre aux composants de le démarrer et onBind()
pour permettre 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 tout composant peut utiliser une activité en la démarrant avec un Intent
. Cependant, vous pouvez déclarer le service comme privé dans le fichier manifeste et bloquer l’accès des autres applications.Ceci est discuté plus en détail dans la section sur la déclaration du service dans leur manifeste.
Choisir entre un service et un thread
Un service est simplement un composant qui peut fonctionner en arrière-plan, même lorsque l’utilisateur n’interagit pas avec votre application, donc vous devriez créer un service seulement si c’est ce dont vous avez besoin.
Si vous devez effectuer un travail en dehors de votre thread principal, mais seulement pendant que l’utilisateur interagit avec votre application, vous devriez plutôt créer un nouveau thread dans le contexte d’un autre composant de l’application. Par exemple, si vous voulez jouer de la musique, mais seulement pendant que 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()
.Envisagez également d’utiliser les pools de threads et les exécuteurs du paquet java.util.concurrent
ou les coroutines Kotlin au lieu de la classe traditionnelleThread
. Consultez le documentThreading on Android pour plus d’informations sur le déplacement de l’exécution vers les threads d’arrière-plan.
N’oubliez pas que si vous utilisez un service, il s’exécute toujours dans le thread principal de votre application par défaut, donc vous devez toujours créer un nouveau thread dans le service s’il effectue des opérations intensives ou bloquantes.
Les bases
Pour créer un service, vous devez créer une sous-classe de Service
ou utiliser une de ses sous-classes existantes. Dans votre implémentation, vous devez surcharger certaines méthodes de rappel qui gèrent les aspects clés du cycle de vie du service et fournir un mécanisme qui permet aux composants de se lier au service, le cas échéant. Voici les méthodes de rappel les plus importantes que vous devez surcharger:
onStartCommand()
Le système invoque cette méthode en appelantstartService()
lorsqu’un autre composant (tel qu’une activité) demande que le service soit démarré.Lorsque cette méthode s’exécute, le service est démarré et peut fonctionner en arrière-plan indéfiniment. Si vous implémentez cette méthode, il est de votre responsabilité d’arrêter le service lorsque son travail est terminé en appelantstopSelf()
oustopService()
. Si vous voulez seulement fournir une liaison, vous n’avez pas besoin d’implémenter cette méthode.onBind()
Le système invoque cette méthode en appelantbindService()
lorsqu’un autre composant veut se lier au service (par exemple pour effectuer un RPC).Dans votre implémentation de cette méthode, vous devez fournir une interface que les clients utilisent pour communiquer avec le service en retournant unIBinder
. Vous devez toujoursimplémenter cette méthode ; cependant, si vous ne voulez pas autoriser la liaison, vous devez retournernull.onCreate()
Le système invoque cette méthode pour effectuer des procédures de configuration uniques lorsque le service estinitialement créé (avant qu’il n’appelle soitonStartCommand()
soitonBind()
). Si le service est déjà en cours d’exécution, cette méthode n’est pas appelée.onDestroy()
Le système invoque cette méthode lorsque le service n’est plus utilisé et qu’il est détruit.Votre service devrait implémenter cette méthode pour nettoyer toutes les ressources telles que les threads, les registeredlisteners, ou les récepteurs. C’est le 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 servicecontinue à s’exécuter jusqu’à ce qu’il s’arrête avec stopSelf()
ou qu’un autrecomposant l’arrête en appelant stopService()
.
Si un composant appellebindService()
pour créer le service et que onStartCommand()
n’est pas appelé, le service s’exécutesoniquement tant que le composant est lié à lui. Après que le service est délié de tous ses clients,le système le détruit.
Le système Android arrête un service uniquement lorsque la mémoire est faible et qu’il doit récupérer les ressources système pour l’activité qui a le focus utilisateur. Si le service est lié à une activité qui a le focus utilisateur, il est moins susceptible d’être tué ; si le service est déclaré pour s’exécuter au premier plan, il est rarement tué.Si le service est démarré et s’exécute longtemps, le système abaisse sa position dans la liste des tâches d’arrière-plan au fil du temps, et le service devient très susceptible d’être tué – si votre service est démarré, vous devez le concevoir pour gérer gracieusement les redémarrages par le système. Si le système tue votre service, il le redémarre dès que les ressources deviennent disponibles, mais cela dépend aussi de la valeur que vous renvoyez de onStartCommand()
. Pour plus d’informations sur les cas où le système peut détruire un service, consultez le document Processus et Threading.
Dans les sections suivantes, vous verrez comment vous pouvez créer les méthodes de servicestartService()
etbindService()
, ainsi que comment les utiliser à partir d’autres composants d’application.
Déclarer un service dans le 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>
comme enfant de l’élément <application>
. Voici un exemple :
<manifest ... > ... <application ... > <service android:name=".ExampleService" /> ... </application></manifest>
Voir la référence de l’élément <service>
pour plus d’informations sur la déclaration de votre service dans le manifeste.
Il existe d’autres attributs que vous pouvez inclure 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 la classe du service. Après avoir publié votre application, laissez ce nom inchangé pour éviter le risque de casser le code en raison de la dépendance à des intentions explicites pour démarrer ou lier le service (lisez le billet de blog, ThingsThat Cannot Change).
Attention : Pour garantir la sécurité de votre application, utilisez toujours une intention explicite lors du démarrage d’un Service
et ne déclarez pas de filtres d’intention pour vos services. L’utilisation d’une intention implicite pour démarrer un service constitue un risque pour la sécurité car vous ne pouvez pas être certain du service qui répond à l’intention, et l’utilisateur ne peut pas voir quel service démarre. À partir d’Android 5.0 (niveau 21 de l’API), le système lève une exception si vous appelezbindService()
avec une intention implicite.
Vous pouvez vous assurer que votre service est disponible uniquement pour votre application en incluant l’attribut android:exported
et en le définissant à false
. Cela empêche effectivement les autres apps de démarrer votre service, même en utilisant une intention explicite.
Note : Les utilisateurs peuvent voir quels services sont exécutés sur leur appareil. S’ils voient un service qu’ils ne reconnaissent pas ou auquel ils ne font pas confiance, ils peuvent arrêter le service. Afin d’éviter que votre service soit arrêté accidentellement par les utilisateurs, vous devez ajouter l’attribut android:description
à l’élément <service>
de votre manifeste d’application. Dans la description, fournissez une courte phrase expliquant ce que fait le service et quels avantages il fournit.
Création d’un service démarré
Un service démarré est un service qu’un autre composant démarre en appelant startService()
, ce qui entraîne un appel à la méthodeonStartCommand()
du service.
Lorsqu’un service est démarré, il a un cycle de vie indépendant du composant qui l’a démarré. Le service peut fonctionner en arrière-plan indéfiniment, même si le composant qui l’a démarré est détruit. En tant que tel, le service doit s’arrêter lorsque son travail est terminé 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 passant un Intent
qui spécifie le service et inclut 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é ait besoin d’enregistrer certaines données dans une base de données en ligne. L’activité peut démarrer un service compagnon et lui fournir les données à sauvegarder en passant une intention à startService()
. Le service reçoit l’intention dans onStartCommand()
, se connecte à l’Internet et effectue la transaction de la base de données. Lorsque la transaction est 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êmeapplication, le service ralentit les performances de l’activité. Pour éviter d’impacter les performances de l’application, démarrez un nouveau thread à l’intérieur du 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 thread 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é que votre application exécute.
Le framework Android fournit également la sous-classe IntentService
de Service
qui utilise un threadworker pour traiter toutes les demandes 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 bien à partir d’Android 8 Oreo, en raison de l’introduction de limites d’exécution en arrière-plan.De plus, elle est dépréciée à partir d’Android 11.Vous pouvez utiliser JobIntentService en remplacement de IntentService
qui est compatible avec les nouvelles versions d’Android.
Les sections suivantes décrivent comment vous pouvez mettre en œuvre votre propre service personnalisé, cependant vous devriez fortement envisager d’utiliser WorkManager à la place pour la plupart des cas d’utilisation. Consultez le guide du traitement en arrière-plan sur Androidpour voir s’il existe une solution qui correspond à vos besoins.
Extension de la classe Service
Vous pouvez étendre la classe Service
pour traiter chaque intention entrante. 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(); }}
Le code de l’exemple traite tous les appels entrants dans onStartCommand()
et poste le travail à un Handler
fonctionnant sur un thread d’arrière-plan. Il fonctionne comme un IntentService
et traite toutes les demandes en série, l’une après l’autre.Vous pourriez modifier le code pour exécuter le travail sur un pool de threads, par exemple, si vous souhaitez exécuter plusieurs demandes simultanément.
Notez que la méthode onStartCommand()
doit retourner un nombre entier. Le nombre entier est une valeur qui décrit comment le système doit poursuivre le service dans le cas où le système le tue. La valeur de retour de onStartCommand()
doit être l’une des constantes suivantes :
START_NOT_STICKY
Si le système tue le service après le retour deonStartCommand()
, ne recréez pas le service à moins qu’il y ait des événements en attente à délivrer. C’est l’option la plus sûre pour éviter d’exécuter votre service quand ce n’est pas nécessaireet quand votre application peut simplement relancer les travaux non terminés.START_STICKY
Si le système tue le service après le retour deonStartCommand()
, recréez le service et appelezonStartCommand()
, mais ne redélivrez pas la dernière intention.Au lieu de cela, le système appelleonStartCommand()
avec une intentionull à moins qu’il y ait des intents en attente pour démarrer le service. Dans ce cas, ces intentions sont délivrées. Cela convient aux lecteurs multimédias (ou des services similaires) qui n’exécutent pas de commandes mais qui tournent indéfiniment et attendent un travail.START_REDELIVER_INTENT
Si le système tue le service après le retour deonStartCommand()
, recréez le service et appelezonStartCommand()
avec la dernière intention qui a été livrée à ce service. Toutes les intentions en attente sont livrées à leur tour. Cela convient aux services qui effectuent activement un travail qui doit être immédiatement repris, comme le téléchargement d’un fichier.
Pour plus de détails sur ces valeurs de retour, voir la documentation référencée lié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 passant 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 26 de l’API ou plus, le système impose des restrictions sur l’utilisation ou la création de services d’arrière-plan, sauf si l’application elle-même est au premier plan. Si une app doit créer un service de premier plan, elle doit appeler startForegroundService()
. Cette méthode crée un service d’arrière-plan, mais la méthode signale au système que le service va se promouvoir au premier plan. Une fois que le service a été créé, il doit appeler sa méthode startForeground()
dans les cinq secondes.
Par exemple, une activité peut démarrer le service d’exemple de la section précédente (HelloService
) en utilisant une intention explicite avec startService()
, comme indiqué ici :
Kotlin
Intent(this, HelloService::class.java).also { intent -> startService(intent)}
Java
Intent intent = new Intent(this, HelloService.class);startService(intent);
La méthode startService()
revient 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 il appelleonStartCommand()
.
Si le service ne fournit pas également de liaison, l’intention qui est délivrée avec startService()
est le seul mode de communication entre le composant applicatif et le service. Cependant, si vous voulez 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 lebroadcast pour délivrer un résultat.
Des demandes multiples pour démarrer le service entraînent des appels multiples correspondants auonStartCommand()
du service. Cependant, une seule demande pour arrêter le service (avec stopSelf()
ou stopService()
) est nécessaire pour l’arrêter.
Arrêter un service
Un service démarré doit gérer son propre cycle de vie. C’est-à-dire que le système ne s’arrête pas pour détruire le service sauf s’il doit récupérer la mémoire système et que le servicecontinue à s’exécuter après le retour de onStartCommand()
. Le service doit s’arrêter lui-même en appelant stopSelf()
, ou un autrecomposant peut l’arrêter en appelant stopService()
.
Une fois qu’on lui demande de s’arrêter avec stopSelf()
ou stopService()
, le système détruit le service dès que possible.
Si votre service traite plusieurs demandes à onStartCommand()
simultanément, vous ne devriez pas arrêter le service lorsque vous avez fini de traiter une demande de démarrage, car vous pourriez avoir reçu une nouvelle demande de démarrage (l’arrêt à la fin de la première demande mettrait fin à la seconde). Pour éviter ce problème, vous pouvez utiliser stopSelf(int)
pour vous assurer que votre demande d’arrêt du service est toujours basée sur la demande de démarrage la plus récente. C’est-à-dire que lorsque vous appelez stopSelf(int)
, vous passez l’ID de la demande de démarrage (la startId
délivrée à onStartCommand()
) à laquelle votre demande d’arrêtcorrespond. Ensuite, si le service reçoit une nouvelle demande de démarrage avant que vous 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 lorsqu’elle a fini de travailler.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 si jamais il reçoit un appel à onStartCommand()
.
Pour plus d’informations sur le cycle de vie d’un service, consultez la section ci-dessous sur la gestion du cycle de vie d’un service.
Création d’un service lié
Un service lié est un service qui permet aux composants d’application de se lier à lui en appelant bindService()
pour créer une connexion de longue durée.Il ne permet généralement pas aux composants de le 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 par le biais de 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. D’autres composants applicatifs peuvent alors appelerbindService()
pour récupérer l’interface et commencer à appeler des méthodes sur le service. Le service ne vit que pour servir le composant applicatif qui lui est lié, donc lorsqu’il n’y a plus de composants liés au service, le système 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é par 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 retourner à partir de la méthode de rappel onBind()
. Après que le client ait reçu le IBinder
, il peut commencer à interagir avec le service à travers cette interface.
Plusieurs clients peuvent se lier au service simultanément. Lorsqu’un client a fini d’interagir avec le service, il appelle unbindService()
pour se délier.Lorsqu’il n’y a plus de clients liés au service, le système détruit le service.
Il existe plusieurs façons d’implémenter un service lié, et l’implémentation est plus compliquée qu’un service démarré. Pour ces raisons, la discussion sur les services liés apparaît dans un document séparé sur les services liés.
Envoyer des notifications à l’utilisateur
Lorsqu’un service est en cours d’exécution, il peut notifier l’utilisateur d’événements en utilisant des notifications de toast ou des notifications de barre d’état.
Une notification de toast est un message qui apparaît à la surface de la fenêtre actuelle pendant seulement un instant avant de disparaître. Une notification de barre d’état fournit une icône dans la barre d’état avec un message, que l’utilisateur peut sélectionner afin de prendre une action (telle que le démarrage d’une activité).
En général, une notification de barre d’état est la meilleure technique à utiliser lorsque le travail en arrière-plan, tel que le téléchargement d’un fichier, est terminé, et que l’utilisateur peut maintenant agir dessus. Lorsque l’utilisateur sélectionne la notification dans la vue étendue, la notification peut démarrer une activité(par exemple pour afficher le fichier téléchargé).
Voir les guides du développeur Toast Notifications ou Status Bar Notifications pour plus d’informations.
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 important que vous accordiez 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 conscient.
Le cycle de vie d’un service – de sa création à sa destruction – peut suivre l’un ou l’autre de ces deux chemins :
- Un service démarré
Le service est créé lorsqu’un autre composant appelle
startService()
. Le service s’exécute alors indéfiniment et doit s’arrêter de lui-même 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 alors avec le service par l’intermédiaire d’une interfaceIBinder
. Le client peut fermer la connexion en appelantunbindService()
. Plusieurs clients peuvent se lier au même service et lorsque tous se libèrent, le système détruit le service. Le service n’a pas besoin de s’arrêter lui-même.
Ces deux chemins ne sont pas entièrement séparés. Vous pouvez vous lier à un service qui est déjà démarré avec startService()
. Par exemple, vous pouvez démarrer un service de musique de fond en appelant startService()
avec un Intent
qui identifie la musique à jouer. Plus tard, éventuellement lorsque l’utilisateur veut exercer un certain contrôle sur le lecteur ou obtenir des informations sur la chanson en cours, une activité peut se lier au service en appelant bindService()
. Dans des cas comme celui-ci, stopService()
ou stopSelf()
n’arrête pas réellement le service jusqu’à ce que tous les clients se délient.
Implémentation des callbacks du cycle de vie
Comme une activité, un service a des méthodes de callback du cycle de vie que vous pouvez implémenter pour surveiller les changements dans l’état du service et effectuer le travail aux moments appropriés. Le squelette de service suivant démontre 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 fun () { // The service is being created } override fun (intent: Intent?, flags: Int, startId: Int): Int { // The service is starting, due to a call to startService() return startMode } override fun (intent: Intent): IBinder? { // A client is binding to the service with bindService() return binder } override fun (intent: Intent): Boolean { // All clients have unbound with unbindService() return allowRebind } override fun (intent: Intent) { // A client is binding to the service with bindService(), // after onUnbind() has already been called } override fun () { // 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 () { // The service is being created } @Override public int (Intent intent, int flags, int startId) { // The service is starting, due to a call to return startMode; } @Override public IBinder (Intent intent) { // A client is binding to the service with return binder; } @Override public boolean (Intent intent) { // All clients have unbound with return allowRebind; } @Override public void (Intent intent) { // A client is binding to the service with , // after onUnbind() has already been called } @Override public void () { // The service is no longer used and is being destroyed }}
Note : Contrairement aux méthodes de rappel du cycle de vie des activités, vous n’êtes pas obligé d’appeler l’implémentation de la superclasse de ces méthodes de rappel.
Figure 2. Le cycle de vie des services. Le diagramme de gauche montre le cycle de vie lorsque le service est créé avec startService()
et le diagramme de droite montre le cycle de vie lorsque le service est créé avec bindService()
.
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, quelle que soit la façon dont il est démarré, peut potentiellement permettre aux clients de se lier à lui.Un service qui a été initialement démarré avec onStartCommand()
(par un client appelant startService()
)peut toujours recevoir un appel à onBind()
(lorsqu’un client appellebindService()
).
En implémentant ces méthodes, vous pouvez surveiller ces deux boucles imbriquées du cycle de vie du service :
- La vie entière d’un service se produit entre le moment où
onCreate()
est appelé et le moment oùonDestroy()
revient. Comme une activité, un service fait sa configuration initiale dansonCreate()
et libère toutes les ressources restantes dansonDestroy()
. Par exemple, un service de lecture de musique peut créer le fil où la musique est jouée dansonCreate()
, puis il peut arrêter le fil dansonDestroy()
.Note : 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 laIntent
qui a été passée à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()
revient.
Note : Bien qu’un service démarré soit arrêté par un appel à stopSelf()
ou stopService()
, il n’y a pas de rappel respectif pour ce service (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 callback reçu.
Pour plus d’informations sur la création d’un service qui fournit une liaison, consultez le document Bound Services,qui comprend plus d’informations sur la méthode onRebind()
callback dans la section sur la gestion du cycle de vie d’un service lié.