Un service lié est le serveur d'une interface client-serveur. Il permet à des composants tels que des activités de se lier au service, d'envoyer des requêtes, de recevoir des réponses et d'effectuer une communication inter-processus (IPC). Un service lié ne vit généralement que lorsqu'il diffuse un autre composant d'application et ne s'exécute pas indéfiniment en arrière-plan.
Ce document explique comment créer un service lié, y compris comment lier le service à partir d'autres composants d'application. Pour en savoir plus sur les services en général, par exemple sur la façon d'envoyer des notifications à partir d'un service et de configurer l'exécution du service au premier plan, consultez la présentation des services.
Principes de base
Un service lié est une implémentation de la classe Service qui permet à d'autres applications de s'y lier et d'interagir avec lui. Pour fournir une liaison pour un service, vous devez implémenter la méthode de rappel onBind(). Cette méthode renvoie un objet IBinder qui définit l'interface de programmation que les clients peuvent utiliser pour interagir avec le service.
Liaison à un service démarré
Comme indiqué dans la section Présentation des services, vous pouvez créer un service à la fois démarré et lié. Autrement dit, vous pouvez démarrer un service en appelant startService(), ce qui permet au service de s'exécuter indéfiniment. Vous pouvez également autoriser un client à se lier au service en appelant bindService().
Si vous autorisez le démarrage et la liaison de votre service, le système ne détruit pas le service lorsque tous les clients se dissocient.
Vous devez l'arrêter explicitement en appelant stopSelf() ou stopService().
Bien que vous implémentiez généralement onBind()
ou onStartCommand(), il est parfois nécessaire d'implémenter les deux. Par exemple, un lecteur de musique peut trouver utile de laisser son service s'exécuter indéfiniment et de fournir une liaison. De cette façon, une activité peut démarrer le service pour lire de la musique, et la musique continue d'être lue même si l'utilisateur quitte l'application. Ensuite, lorsque l'utilisateur revient dans l'application, l'activité peut se lier au service pour reprendre le contrôle de la lecture.
Pour en savoir plus sur le cycle de vie du service lors de l'ajout d'une liaison à un service démarré, consultez la section Gérer le cycle de vie d'un service lié.
Un client se lie à un service en appelant bindService(). Dans ce cas, elle doit fournir une implémentation de ServiceConnection, qui surveille la connexion au service. La valeur de retour de bindService() indique si le service demandé existe et si le client est autorisé à y accéder.
Lorsque le système Android crée la connexion entre le client et le service, il appelle onServiceConnected() sur ServiceConnection. La méthode onServiceConnected() inclut un argument IBinder, que le client utilise ensuite pour communiquer avec le service lié.
Vous pouvez connecter plusieurs clients à un service simultanément. Toutefois, le système met en cache le canal de communication du service IBinder.
En d'autres termes, le système appelle la méthode onBind() du service pour générer l'IBinder uniquement lorsque le premier client se lie. Le système transmet ensuite ce même IBinder à tous les clients supplémentaires qui se lient à ce même service, sans appeler à nouveau onBind().
Lorsque le dernier client se dissocie du service, le système détruit le service, sauf si celui-ci a été démarré à l'aide de startService().
La partie la plus importante de l'implémentation de votre service lié consiste à définir l'interface renvoyée par votre méthode de rappel onBind(). La section suivante présente plusieurs façons de définir l'interface IBinder de votre service.
Créer un service lié
Lorsque vous créez un service qui fournit une liaison, vous devez fournir un IBinder qui fournit l'interface de programmation que les clients peuvent utiliser pour interagir avec le service. Vous pouvez définir l'interface de trois manières :
- Étendre la classe Binder
- Si votre service est privé pour votre propre application et s'exécute dans le même processus que le client, ce qui est courant, créez votre interface en étendant la classe
Binderet en renvoyant une instance de celle-ci à partir deonBind(). Le client reçoit leBinderet peut l'utiliser pour accéder directement aux méthodes publiques disponibles dans l'implémentationBinderou dans leService.Il s'agit de la technique privilégiée lorsque votre service n'est qu'un nœud de calcul en arrière-plan pour votre propre application. Le seul cas d'utilisation où cette méthode n'est pas recommandée pour créer votre interface est lorsque votre service est utilisé par d'autres applications ou par des processus distincts.
- Utiliser un Messenger
- Si vous avez besoin que votre interface fonctionne sur différents processus, vous pouvez créer une interface pour le service avec un
Messenger. De cette manière, le service définit unHandlerqui répond à différents types d'objetsMessage.Ce
Handlerest la base d'unMessengerqui peut ensuite partager unIBinderavec le client, ce qui lui permet d'envoyer des commandes au service à l'aide d'objetsMessage. De plus, le client peut définir son propreMessenger, afin que le service puisse renvoyer des messages.Il s'agit du moyen le plus simple d'effectuer une communication inter-processus (IPC), car
Messengermet en file d'attente toutes les requêtes dans un seul thread. Vous n'avez donc pas besoin de concevoir votre service pour qu'il soit thread-safe. - Utiliser AIDL
- Le langage de définition d'interface Android (AIDL) décompose les objets en primitives que le système d'exploitation peut comprendre et les sérialise entre les processus pour effectuer l'IPC. La technique précédente, qui utilise un
Messenger, est en fait basée sur l'AIDL en tant que structure sous-jacente.Comme indiqué dans la section précédente,
Messengercrée une file d'attente de toutes les requêtes client dans un seul thread, de sorte que le service reçoit les requêtes une par une. Toutefois, si vous souhaitez que votre service gère plusieurs requêtes simultanément, vous pouvez utiliser directement AIDL. Dans ce cas, votre service doit être thread-safe et capable d'effectuer du multithreading.Pour utiliser directement l'AIDL, créez un fichier
.aidlqui définit l'interface de programmation. Les outils du SDK Android utilisent ce fichier pour générer une classe abstraite qui implémente l'interface et gère l'IPC, que vous pouvez ensuite étendre dans votre service.
Remarque : Pour la plupart des applications, AIDL n'est pas le meilleur choix pour créer un service lié, car il peut nécessiter des fonctionnalités de multithreading et entraîner une implémentation plus complexe. Par conséquent, ce document n'explique pas comment l'utiliser pour votre service. Si vous êtes certain de devoir utiliser directement l'AIDL, consultez le document AIDL.
Étendre la classe Binder
Si seule l'application locale utilise votre service et qu'elle n'a pas besoin de fonctionner entre les processus, vous pouvez implémenter votre propre classe Binder qui fournit à votre client un accès direct aux méthodes publiques du service.
Remarque : Cela ne fonctionne que si le client et le service se trouvent dans la même application et le même processus, ce qui est le cas le plus courant. Par exemple, cela fonctionne bien pour une application musicale qui doit lier une activité à son propre service qui lit de la musique en arrière-plan.
Voici comment faire :
- Dans votre service, créez une instance de
Binderqui effectue l'une des opérations suivantes :- Contient des méthodes publiques que le client peut appeler.
- Renvoie l'instance
Serviceactuelle, qui comporte des méthodes publiques que le client peut appeler. - Renvoie une instance d'une autre classe hébergée par le service avec des méthodes publiques que le client peut appeler.
- Renvoyez cette instance de
Binderà partir de la méthode de rappelonBind(). - Dans le client, recevez le
Binderde la méthode de rappelonServiceConnected()et passez des appels au service lié à l'aide des méthodes fournies.
Remarque : Le service et le client doivent se trouver dans la même application pour que le client puisse caster l'objet renvoyé et appeler correctement ses API. Le service et le client doivent également se trouver dans le même processus, car cette technique n'effectue aucun marshaling entre les processus.
Par exemple, voici un service qui permet aux clients d'accéder aux méthodes du service via une implémentation Binder :
Kotlin
class LocalService : Service() { // Binder given to clients. private val binder = LocalBinder() // Random number generator. private val mGenerator = Random() /** Method for clients. */ val randomNumber: Int get() = mGenerator.nextInt(100) /** * Class used for the client Binder. Because we know this service always * runs in the same process as its clients, we don't need to deal with IPC. */ inner class LocalBinder : Binder() { // Return this instance of LocalService so clients can call public methods. fun getService(): LocalService = this@LocalService } override fun onBind(intent: Intent): IBinder { return binder } }
Java
public class LocalService extends Service { // Binder given to clients. private final IBinder binder = new LocalBinder(); // Random number generator. private final Random mGenerator = new Random(); /** * Class used for the client Binder. Because we know this service always * runs in the same process as its clients, we don't need to deal with IPC. */ public class LocalBinder extends Binder { LocalService getService() { // Return this instance of LocalService so clients can call public methods. return LocalService.this; } } @Override public IBinder onBind(Intent intent) { return binder; } /** Method for clients. */ public int getRandomNumber() { return mGenerator.nextInt(100); } }
LocalBinder fournit la méthode getService() permettant aux clients de récupérer l'instance actuelle de LocalService. Cela permet aux clients d'appeler des méthodes publiques dans le service. Par exemple, les clients peuvent appeler getRandomNumber() à partir du service.
Voici une activité qui se lie à LocalService et appelle getRandomNumber() lorsqu'un utilisateur clique sur un bouton :
Kotlin
class BindingActivity : Activity() { private var mService: LocalService? = null private var mBound: Boolean = false /** Defines callbacks for service binding, passed to bindService(). */ private val connection = object : ServiceConnection { override fun onServiceConnected(className: ComponentName, service: IBinder) { // We've bound to LocalService, cast the IBinder and get LocalService instance. val binder = service as LocalService.LocalBinder mService = binder.getService() mBound = true } override fun onServiceDisconnected(arg0: ComponentName) { mService = null mBound = false } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.main) } override fun onStart() { super.onStart() // Bind to LocalService. Intent(this, LocalService::class.java).also { intent -> bindService(intent, connection, Context.BIND_AUTO_CREATE) } } override fun onStop() { super.onStop() unbindService(connection) // Release the reference so the service can be garbage-collected once it's // destroyed. onServiceDisconnected() isn't called when the client unbinds. mService = null mBound = false } /** Called when a button is clicked (the button in the layout file attaches to * this method with the android:onClick attribute). */ fun onButtonClick(v: View) { if (mBound) { // Call a method from the LocalService. // However, if this call is something that might hang, then put this request // in a separate thread to avoid slowing down the activity performance. val num: Int = mService?.randomNumber ?: return Toast.makeText(this, "number: $num", Toast.LENGTH_SHORT).show() } } }
Java
public class BindingActivity extends Activity { LocalService mService; boolean mBound = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected void onStart() { super.onStart(); // Bind to LocalService. Intent intent = new Intent(this, LocalService.class); bindService(intent, connection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); unbindService(connection); // Release the reference so the service can be garbage-collected once it's // destroyed. onServiceDisconnected() isn't called when the client unbinds. mService = null; mBound = false; } /** Called when a button is clicked (the button in the layout file attaches to * this method with the android:onClick attribute). */ public void onButtonClick(View v) { if (mBound) { // Call a method from the LocalService. // However, if this call is something that might hang, then put this request // in a separate thread to avoid slowing down the activity performance. int num = mService.getRandomNumber(); Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show(); } } /** Defines callbacks for service binding, passed to bindService(). */ private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { // We've bound to LocalService, cast the IBinder and get LocalService instance. LocalBinder binder = (LocalBinder) service; mService = binder.getService(); mBound = true; } @Override public void onServiceDisconnected(ComponentName arg0) { mService = null; mBound = false; } }; }
L'exemple précédent montre comment le client se lie au service à l'aide d'une implémentation de ServiceConnection et du rappel onServiceConnected(). La section suivante fournit plus d'informations sur ce processus de liaison au service.
Remarque : Dans l'exemple précédent, la méthode onStop() dissocie le client du service et libère la référence du client à celui-ci.
Dissociez les clients des services aux moments appropriés, comme indiqué dans la section Remarques supplémentaires.
Pour obtenir d'autres exemples de code, consultez les classes
LocalService.java et
LocalServiceActivities.java dans ApiDemos.
Utiliser un service de messagerie instantanée
Si votre service doit communiquer avec des processus distants, vous pouvez utiliser un Messenger pour fournir l'interface de votre service. Cette technique vous permet d'effectuer une communication inter-processus (IPC) sans avoir à utiliser l'AIDL.
L'utilisation d'un Messenger pour votre interface est plus simple que l'utilisation d'AIDL, car Messenger met en file d'attente tous les appels au service. Une interface AIDL pure envoie des requêtes simultanées au service, qui doit ensuite gérer le multithreading.
Pour la plupart des applications, le service n'a pas besoin d'effectuer de multithreading. L'utilisation d'un Messenger permet donc au service de gérer un appel à la fois. S'il est important que votre service soit multithread, utilisez AIDL pour définir votre interface.
Voici un récapitulatif de la façon d'utiliser un Messenger :
- Le service implémente un
Handlerqui reçoit un rappel pour chaque appel d'un client. - Le service utilise
Handlerpour créer un objetMessenger(qui est une référence àHandler). Messengercrée unIBinderque le service renvoie aux clients à partir deonBind().- Les clients utilisent
IBinderpour instancierMessenger(qui fait référence àHandlerdu service), que le client utilise pour envoyer des objetsMessageau service. - Le service reçoit chaque
Messagedans sonHandler, plus précisément dans la méthodehandleMessage().
De cette façon, le client ne peut appeler aucune méthode sur le service. À la place, le client envoie des messages (objets Message) que le service reçoit dans son Handler.
Voici un exemple de service qui utilise une interface Messenger :
Kotlin
/** Command to the service to display a message. */ private const val MSG_SAY_HELLO = 1 class MessengerService : Service() { /** * Target we publish for clients to send messages to IncomingHandler. */ private lateinit var mMessenger: Messenger /** * Handler of incoming messages from clients. */ internal class IncomingHandler( context: Context, private val applicationContext: Context = context.applicationContext ) : Handler() { override fun handleMessage(msg: Message) { when (msg.what) { MSG_SAY_HELLO -> Toast.makeText(applicationContext, "hello!", Toast.LENGTH_SHORT).show() else -> super.handleMessage(msg) } } } /** * When binding to the service, we return an interface to our messenger * for sending messages to the service. */ override fun onBind(intent: Intent): IBinder? { Toast.makeText(applicationContext, "binding", Toast.LENGTH_SHORT).show() mMessenger = Messenger(IncomingHandler(this)) return mMessenger.binder } }
Java
public class MessengerService extends Service { /** * Command to the service to display a message. */ static final int MSG_SAY_HELLO = 1; /** * Handler of incoming messages from clients. */ static class IncomingHandler extends Handler { private Context applicationContext; IncomingHandler(Context context) { applicationContext = context.getApplicationContext(); } @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_SAY_HELLO: Toast.makeText(applicationContext, "hello!", Toast.LENGTH_SHORT).show(); break; default: super.handleMessage(msg); } } } /** * Target we publish for clients to send messages to IncomingHandler. */ Messenger mMessenger; /** * When binding to the service, we return an interface to our messenger * for sending messages to the service. */ @Override public IBinder onBind(Intent intent) { Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show(); mMessenger = new Messenger(new IncomingHandler(this)); return mMessenger.getBinder(); } }
La méthode handleMessage() dans Handler est l'endroit où le service reçoit l'Message entrant et décide de l'action à effectuer, en fonction du membre what.
Il suffit au client de créer un Messenger basé sur le IBinder renvoyé par le service et d'envoyer un message à l'aide de send(). Par exemple, voici une activité qui se lie au service et lui envoie le message MSG_SAY_HELLO :
Kotlin
class ActivityMessenger : Activity() { /** Messenger for communicating with the service. */ private var mService: Messenger? = null /** Flag indicating whether we have called bind on the service. */ private var bound: Boolean = false /** * Class for interacting with the main interface of the service. */ private val mConnection = object : ServiceConnection { override fun onServiceConnected(className: ComponentName, service: IBinder) { // This is called when the connection with the service has been // established, giving us the object we can use to // interact with the service. We are communicating with the // service using a Messenger, so here we get a client-side // representation of that from the raw IBinder object. mService = Messenger(service) bound = true } override fun onServiceDisconnected(className: ComponentName) { // This is called when the connection with the service has been // unexpectedly disconnected—that is, its process crashed. mService = null bound = false } } fun sayHello(v: View) { if (!bound) return // Create and send a message to the service, using a supported 'what' value. val msg: Message = Message.obtain(null, MSG_SAY_HELLO, 0, 0) try { mService?.send(msg) } catch (e: RemoteException) { e.printStackTrace() } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.main) } override fun onStart() { super.onStart() // Bind to the service. Intent(this, MessengerService::class.java).also { intent -> bindService(intent, mConnection, Context.BIND_AUTO_CREATE) } } override fun onStop() { super.onStop() // Unbind from the service. if (bound) { unbindService(mConnection) mService = null bound = false } } }
Java
public class ActivityMessenger extends Activity { /** Messenger for communicating with the service. */ Messenger mService = null; /** Flag indicating whether we have called bind on the service. */ boolean bound; /** * Class for interacting with the main interface of the service. */ private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { // This is called when the connection with the service has been // established, giving us the object we can use to // interact with the service. We are communicating with the // service using a Messenger, so here we get a client-side // representation of that from the raw IBinder object. mService = new Messenger(service); bound = true; } public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected—that is, its process crashed. mService = null; bound = false; } }; public void sayHello(View v) { if (!bound) return; // Create and send a message to the service, using a supported 'what' value. Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0); try { mService.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected void onStart() { super.onStart(); // Bind to the service. bindService(new Intent(this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); // Unbind from the service. if (bound) { unbindService(mConnection); mService = null; bound = false; } } }
Cet exemple ne montre pas comment le service peut répondre au client.
Si vous souhaitez que le service réponde, vous devez également créer un Messenger dans le client.
Lorsque le client reçoit le rappel onServiceConnected(), il envoie un Message au service qui inclut le Messenger du client dans le paramètre replyTo de la méthode send().
Vous trouverez un exemple de messagerie bidirectionnelle dans les exemples
MessengerService.java (service) et
MessengerServiceActivities.java (client).
Créer une liaison avec un service
Les composants d'application (clients) peuvent se lier à un service en appelant bindService(). Le système Android appelle ensuite la méthode onBind() du service, qui renvoie un IBinder pour interagir avec le service.
La liaison est asynchrone et bindService() renvoie immédiatement sans renvoyer le IBinder au client. Pour recevoir le IBinder, le client doit créer une instance de ServiceConnection et la transmettre à bindService(). ServiceConnection inclut une méthode de rappel que le système appelle pour diffuser IBinder.
Remarque : Seuls les activités, les services et les fournisseurs de contenu peuvent être liés à un service. Vous ne pouvez pas lier un service à partir d'un broadcast receiver.
Pour effectuer une liaison à un service à partir de votre client, procédez comme suit :
- Mettre en œuvre
ServiceConnectionVotre implémentation doit remplacer deux méthodes de rappel :
onServiceConnected()- Le système appelle cette méthode pour diffuser l'
IBinderrenvoyé par la méthodeonBind()du service. onServiceDisconnected()- Le système Android appelle cette méthode lorsque la connexion au service est perdue de manière inattendue, par exemple lorsque le service plante ou est arrêté. Cette méthode n'est pas appelée lorsque le client annule l'association.
- Appelez
bindService()en transmettant l'implémentation deServiceConnection.Remarque : Si la méthode renvoie "false", votre client n'est pas connecté au service de manière valide. Toutefois, appelez
unbindService()dans votre client. Sinon, votre client empêche le service de s'arrêter lorsqu'il est inactif. - Lorsque le système appelle votre méthode de rappel
onServiceConnected(), vous pouvez commencer à appeler le service à l'aide des méthodes définies par l'interface. - Pour vous déconnecter du service, appelez
unbindService().Si votre client est toujours lié à un service lorsque votre application le détruit, la destruction entraîne la dissociation du client. Il est préférable d'annuler l'association du client dès qu'il a terminé d'interagir avec le service. Cela permet d'arrêter le service inactif. Pour en savoir plus sur les moments appropriés pour lier et dissocier, consultez la section Remarques supplémentaires.
L'exemple suivant connecte le client au service créé précédemment en étendant la classe Binder. Il lui suffit donc de caster le IBinder renvoyé vers la classe LocalBinder et de demander l'instance LocalService :
Kotlin
var mService: LocalService? = null val mConnection = object : ServiceConnection { // Called when the connection with the service is established. override fun onServiceConnected(className: ComponentName, service: IBinder) { // Because we have bound to an explicit // service that is running in our own process, we can // cast its IBinder to a concrete class and directly access it. val binder = service as LocalService.LocalBinder mService = binder.getService() mBound = true } // Called when the connection with the service disconnects unexpectedly. override fun onServiceDisconnected(className: ComponentName) { Log.e(TAG, "onServiceDisconnected") mService = null mBound = false } }
Java
LocalService mService; private ServiceConnection mConnection = new ServiceConnection() { // Called when the connection with the service is established. public void onServiceConnected(ComponentName className, IBinder service) { // Because we have bound to an explicit // service that is running in our own process, we can // cast its IBinder to a concrete class and directly access it. LocalBinder binder = (LocalBinder) service; mService = binder.getService(); mBound = true; } // Called when the connection with the service disconnects unexpectedly. public void onServiceDisconnected(ComponentName className) { Log.e(TAG, "onServiceDisconnected"); mService = null; mBound = false; } };
Avec ce ServiceConnection, le client peut se lier à un service en le transmettant à bindService(), comme illustré dans l'exemple suivant :
Kotlin
Intent(this, LocalService::class.java).also { intent -> bindService(intent, connection, Context.BIND_AUTO_CREATE) }
Java
Intent intent = new Intent(this, LocalService.class); bindService(intent, connection, Context.BIND_AUTO_CREATE);
- Le premier paramètre de
bindService()est unIntentqui nomme explicitement le service à lier.Attention : Si vous utilisez un intent pour créer une liaison à un
Service, assurez-vous que votre application est sécurisée en utilisant un intent explicite. 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 appelezbindService()avec un intent implicite. - Le deuxième paramètre est l'objet
ServiceConnection. - Le troisième paramètre est un indicateur spécifiant les options de la liaison, généralement
BIND_AUTO_CREATE, pour créer le service s'il n'est pas déjà actif. Les autres valeurs possibles sontBIND_DEBUG_UNBIND,BIND_NOT_FOREGROUNDou0pour "aucune".
Remarques supplémentaires
Voici quelques remarques importantes concernant la liaison à un service :
- Interceptez toujours les exceptions
DeadObjectException, qui sont générées lorsque la connexion est interrompue. Il s'agit de la seule exception générée par les méthodes distantes. - Les objets sont comptés par référence dans les processus.
- En général, vous associez la liaison et l'annulation de la liaison lors des moments de démarrage et d'arrêt correspondants du cycle de vie du client, comme décrit dans les exemples suivants :
- Si vous n'avez besoin d'interagir avec le service que lorsque votre activité est visible, effectuez la liaison pendant
onStart()et la dissociation pendantonStop(). - Si vous souhaitez que votre activité reçoive des réponses même lorsqu'elle est arrêtée en arrière-plan, effectuez la liaison pendant
onCreate()et annulez-la pendantonDestroy(). Sachez que cela implique que votre activité doit utiliser le service pendant toute sa durée d'exécution, même en arrière-plan. Ainsi, lorsque le service se trouve dans un autre processus, vous augmentez le poids du processus, qui est plus susceptible d'être arrêté par le système.
Remarque : En général, vous ne devez pas lier et dissocier pendant les rappels
onResume()etonPause()de votre activité, car ces rappels se produisent à chaque transition de cycle de vie. Réduisez au minimum le traitement qui se produit lors de ces transitions.De plus, si plusieurs activités de votre application sont liées au même service et qu'une transition se produit entre deux de ces activités, le service peut être détruit et recréé lorsque l'activité en cours est dissociée (pendant la mise en pause) avant que la suivante ne soit liée (pendant la reprise). Cette transition d'activité pour la façon dont les activités coordonnent leurs cycles de vie est décrite dans Cycle de vie d'une activité.
- Si vous n'avez besoin d'interagir avec le service que lorsque votre activité est visible, effectuez la liaison pendant
Pour obtenir d'autres exemples de code montrant comment effectuer une liaison à un service, consultez la classe
RemoteService.java dans ApiDemos.
Gérer le cycle de vie d'un service lié
Lorsqu'un service est dissocié de tous les clients, le système Android le détruit (sauf s'il a été démarré à l'aide de startService()). Vous n'avez donc pas besoin de gérer le cycle de vie de votre service s'il s'agit d'un service purement lié. Le système Android le gère pour vous selon qu'il est lié ou non à des clients.
Toutefois, si vous choisissez d'implémenter la méthode de rappel onStartCommand(), vous devez arrêter explicitement le service, car il est désormais considéré comme démarré. Dans ce cas, le service s'exécute jusqu'à ce qu'il s'arrête lui-même avec stopSelf() ou qu'un autre composant appelle stopService(), qu'il soit lié ou non à des clients.
De plus, si votre service est démarré et accepte la liaison, lorsque le système appelle votre méthode onUnbind(), vous pouvez éventuellement renvoyer true si vous souhaitez recevoir un appel à onRebind() la prochaine fois qu'un client se liera au service. onRebind() renvoie "void", mais le client reçoit toujours le IBinder dans son rappel onServiceConnected().
La figure suivante illustre la logique de ce type de cycle de vie.
Pour en savoir plus sur le cycle de vie d'un service démarré, consultez la présentation des services.