Un servizio associato è il server in un'interfaccia client-server. Consente a componenti come attività di associarsi al servizio, inviare richieste, ricevere risposte ed eseguire comunicazione tra processi (IPC). In genere, un servizio associato è attivo solo mentre gestisce un altro componente dell'applicazione e non viene eseguito in background a tempo indeterminato.
Questo documento descrive come creare un servizio associato, incluse le modalità di associazione al servizio da altri componenti dell'applicazione. Per ulteriori informazioni sui servizi in generale, ad esempio su come inviare le notifiche di un servizio e impostare il servizio per l'esecuzione in primo piano, consulta la panoramica dei servizi.
Nozioni di base
Un servizio associato è un'implementazione della classe Service
che consente ad
altre applicazioni di associarsi e interagire. Per fornire l'associazione di un servizio, devi implementare il metodo di callback onBind()
. Questo metodo restituisce un oggetto IBinder
che definisce l'interfaccia di programmazione che i client possono utilizzare per interagire con il servizio.
Associazione a un servizio avviato
Come descritto nella panoramica dei servizi,
puoi creare un servizio avviato e associato. In altre parole, puoi avviare un servizio chiamando startService()
, che consente un'esecuzione illimitata del servizio. Puoi anche consentire a un client di associarsi al servizio chiamando bindService()
.
Se consenti l'avvio e l'associazione del servizio, all'avvio il sistema non elimina il servizio quando tutti i client si svincolano.
Devi invece interrompere esplicitamente il servizio chiamando stopSelf()
o stopService()
.
Anche se di solito implementi onBind()
o onStartCommand()
, a volte è
necessario
implementare entrambi. Ad esempio, un music player potrebbe trovare utile consentire l'esecuzione continua del suo servizio e anche fornire associazioni. In questo modo, un'attività può avviare il servizio per riprodurre un po' di musica e la musica continua a essere riprodotta anche se l'utente esce dall'applicazione. Quindi, quando l'utente torna all'applicazione, l'attività può essere associata al servizio per riprendere il controllo della riproduzione.
Per saperne di più sul ciclo di vita del servizio quando aggiungi l'associazione a un servizio avviato, consulta la sezione Gestire il ciclo di vita di un servizio associato.
Un client si associa a un servizio chiamando
bindService()
. Quando lo fa, deve
fornire un'implementazione di ServiceConnection
, che
monitora la connessione con il servizio. Il valore restituito bindService()
indica se il servizio richiesto esiste e se il client è autorizzato ad accedervi.
Quando
il sistema Android crea la connessione tra il client e il servizio, chiama onServiceConnected()
su ServiceConnection
. Il metodo onServiceConnected()
include un argomento IBinder
, che il client utilizza quindi per comunicare con il servizio associato.
Puoi connettere più client contemporaneamente a un servizio. Tuttavia, il sistema memorizza nella cache il canale di comunicazione del servizio IBinder
.
In altre parole, il sistema chiama il metodo onBind()
del servizio per generare IBinder
solo quando il primo client si associa. Il sistema quindi fornisce lo stesso IBinder
a tutti i client aggiuntivi associati allo stesso servizio, senza chiamare di nuovo onBind()
.
Quando l'ultimo client si svincola dal servizio, il sistema elimina il servizio, a meno che il servizio non sia stato avviato utilizzando startService()
.
La parte più importante dell'implementazione del servizio associato è la definizione dell'interfaccia restituita dal metodo di callback onBind()
. La seguente sezione illustra i diversi modi in cui puoi definire l'interfaccia IBinder
del tuo servizio.
Crea un servizio associato
Quando crei un servizio che fornisce associazione, devi fornire un IBinder
che fornisce l'interfaccia di programmazione che i client possono utilizzare per interagire con il servizio. Esistono tre modi per definire l'interfaccia:
- Estendi la classe Binder
- Se il servizio è privato per la tua applicazione e viene eseguito nello stesso processo
del client, operazione comune, crea l'interfaccia estendendo la classe
Binder
e restituendo un'istanza daonBind()
. Il client riceveBinder
e può utilizzarlo per accedere direttamente ai metodi pubblici disponibili nell'implementazione diBinder
o inService
.Questa è la tecnica preferita se il servizio è semplicemente un worker in background per la tua applicazione. L'unico caso d'uso in cui non è il modo migliore per creare la tua interfaccia è se il servizio è utilizzato da altre applicazioni o tra processi separati.
- Utilizzare un Messenger
- Se vuoi che l'interfaccia funzioni su diversi processi, puoi creare un'interfaccia per il servizio con un
Messenger
. In questo modo, il servizio definisce unHandler
che risponde a diversi tipi di oggettiMessage
.Questo
Handler
è la base perMessenger
che può condividere unIBinder
con il client, consentendo al client di inviare comandi al servizio utilizzando gli oggettiMessage
. Inoltre, il client può definire unMessenger
personale, in modo che il servizio possa restituire i messaggi.Questo è il modo più semplice per eseguire la comunicazione tra processi (IPC), perché
Messenger
accoda tutte le richieste in un unico thread, così non devi progettare il tuo servizio per essere thread-safe. - Usa AIDL
- Android Interface Definition Language (AIDL) scompone gli oggetti in primitivi che il sistema operativo è in grado di comprendere e li raggruppa nei vari processi per eseguire l'IPC. La tecnica precedente, utilizzando un
Messenger
, si basa in realtà su AIDL come struttura sottostante.Come menzionato nella sezione precedente,
Messenger
crea una coda di tutte le richieste del client in un singolo thread, in modo che il servizio riceva le richieste una alla volta. Se, tuttavia, vuoi che il tuo servizio gestisca più richieste contemporaneamente, puoi utilizzare direttamente AIDL. In questo caso, il servizio deve essere thread-safe e capacità di multi-threading.Per utilizzare direttamente AIDL, crea un file
.aidl
che definisca l'interfaccia di programmazione. Gli strumenti SDK Android utilizzano questo file per generare una classe astratta che implementa l'interfaccia e gestisce l'IPC, che puoi poi estendere all'interno del tuo servizio.
Nota: per la maggior parte delle applicazioni, AIDL non è la scelta migliore per creare un servizio associato, perché potrebbe richiedere funzionalità di multithreading e comportare un'implementazione più complicata. Pertanto, questo documento non illustra come utilizzarlo per il tuo servizio. Se hai la certezza di dover utilizzare direttamente AIDL, consulta il documento AIDL.
Estendi la classe Binder
Se solo l'applicazione locale utilizza il tuo servizio e non deve funzionare su più processi, puoi implementare la tua classe Binder
che fornisca al client l'accesso diretto ai metodi pubblici nel servizio.
Nota: funziona solo se il client e il servizio si trovano nella stessa applicazione e nello stesso processo, il che è più comune. Ad esempio, questo metodo funziona bene per un'applicazione musicale che deve associare un'attività al proprio servizio che riproduce musica in background.
Ecco come impostarlo:
- Nel servizio, crea un'istanza di
Binder
che esegua una delle seguenti operazioni:- Contiene metodi pubblici che il client può chiamare.
- Restituisce l'istanza
Service
corrente, che dispone di metodi pubblici che il client può chiamare. - Restituisce un'istanza di un'altra classe ospitata dal servizio con metodi pubblici che il client può chiamare.
- Restituisci questa istanza di
Binder
dal metodo di callbackonBind()
. - Nel client, ricevi
Binder
dal metodo di callbackonServiceConnected()
ed effettua chiamate al servizio associato utilizzando i metodi forniti.
Nota: il servizio e il client devono trovarsi nella stessa applicazione in modo che il client possa trasmettere l'oggetto restituito e chiamare correttamente le API. Anche il servizio e il client devono trovarsi nello stesso processo, perché questa tecnica non esegue alcun marshalling tra processi.
Ad esempio, ecco un servizio che fornisce ai client l'accesso ai metodi nel servizio tramite un'implementazione 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
fornisce il metodo getService()
per consentire ai client di recuperare l'istanza corrente di LocalService
. Ciò consente ai client di chiamare i metodi pubblici nel servizio. Ad esempio, i clienti possono chiamare getRandomNumber()
dal servizio.
Ecco un'attività che si associa a LocalService
e chiama getRandomNumber()
quando un utente fa clic su un pulsante:
Kotlin
class BindingActivity : Activity() { private lateinit var mService: LocalService 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) { 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) 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 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); 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) { mBound = false; } }; }
L'esempio precedente mostra come il client si associa al servizio utilizzando un'implementazione di ServiceConnection
e del callback onServiceConnected()
. La sezione successiva fornisce ulteriori informazioni su questa procedura di associazione al servizio.
Nota: nell'esempio precedente, il metodo onStop()
svincola il client dal servizio.
Svincola i client dai servizi al momento opportuno, come descritto nella sezione Note aggiuntive.
Per ulteriore codice di esempio, consulta la classe
LocalService.java
e la classe
LocalServiceActivities.java
in ApiDemos.
Usa un Messenger
Se hai bisogno che il tuo servizio comunichi con processi remoti, puoi utilizzare un
Messenger
per fornire l'interfaccia per il servizio. Questa tecnica consente di eseguire la comunicazione tra processi (IPC) senza dover utilizzare AIDL.
Utilizzare Messenger
per la tua interfaccia è più semplice rispetto all'uso di AIDL perché Messenger
mette in coda tutte le chiamate al servizio. Un'interfaccia AIDL pura invia richieste simultanee al servizio, che deve quindi gestire il multithreading.
Per la maggior parte delle applicazioni, il servizio non ha bisogno di eseguire il multi-threading, quindi l'utilizzo di un Messenger
consente al servizio di gestire una chiamata alla volta. Se è importante che il servizio sia multithread, utilizza AIDL per definire l'interfaccia.
Ecco un riepilogo di come utilizzare Messenger
:
- Il servizio implementa un
Handler
che riceve un callback per ogni chiamata da un client. - Il servizio utilizza
Handler
per creare un oggettoMessenger
(che è un riferimento aHandler
). Messenger
crea un valoreIBinder
che il servizio restituisce ai client daonBind()
.- I client utilizzano
IBinder
per creare un'istanza diMessenger
(che fa riferimento all'Handler
del servizio), che il client utilizza per inviare gli oggettiMessage
al servizio. - Il servizio riceve ogni
Message
nel proprioHandler
, più precisamente nel metodohandleMessage()
.
In questo modo, il client non ha metodi per chiamare il servizio. Invece, il client consegna i messaggi (Message
oggetti) che il servizio riceve nel suo Handler
.
Di seguito è riportato un semplice servizio di esempio che utilizza un'interfaccia 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(); } }
Il metodo handleMessage()
in Handler
è il luogo in cui il servizio riceve i Message
in entrata e decide cosa fare in base al membro what
.
Tutto ciò che un client deve fare è creare un Messenger
basato sul IBinder
restituito dal servizio e inviare un messaggio utilizzando send()
. Ad esempio, ecco un'attività che si associa al
servizio e recapita il messaggio MSG_SAY_HELLO
a quest'ultimo:
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) 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); bound = false; } } }
Questo esempio non mostra in che modo il servizio può rispondere al client.
Se vuoi che il servizio risponda, devi anche creare un Messenger
nel client.
Quando il client riceve il callback onServiceConnected()
, invia un Message
al servizio che include Messenger
nel parametro replyTo
del metodo send()
.
Puoi vedere un esempio di come fornire messaggistica bidirezionale negli esempi di
MessengerService.java
(servizio) e
MessengerServiceActivities.java
(client).
Associazione a un servizio
I componenti dell'applicazione (client) possono essere associati a un servizio chiamando
bindService()
. Il sistema Android chiama quindi il metodo onBind()
del servizio, che restituisce un valore IBinder
per l'interazione con il servizio.
L'associazione è asincrona e bindService()
restituisce immediatamente senza restituire IBinder
al client. Per ricevere IBinder
, il client deve creare un'istanza di ServiceConnection
e passarla a bindService()
. ServiceConnection
include un metodo di callback che il sistema chiama per recapitare l'IBinder
.
Nota: solo le attività, i servizi e i fornitori di contenuti possono essere associati a un servizio; non puoi eseguire l'associazione a un servizio da un ricevitore di trasmissione.
Per eseguire l'associazione a un servizio del tuo client, segui questi passaggi:
- Implementa
ServiceConnection
.L'implementazione deve sostituire due metodi di callback:
onServiceConnected()
- Il sistema esegue la chiamata per consegnare il valore
IBinder
restituito dal metodoonBind()
del servizio. onServiceDisconnected()
- Il sistema Android chiama questa funzionalità quando la connessione al servizio si interrompe inaspettatamente, ad esempio quando il servizio si arresta in modo anomalo o viene interrotto. Questa azione non viene chiamata quando il client si svincola.
- Chiama
bindService()
, superando l'implementazioneServiceConnection
.Nota: se il metodo restituisce false, il client non ha una connessione valida al servizio. Tuttavia, chiama
unbindService()
nel tuo client. In caso contrario, il client impedisce l'arresto del servizio quando è inattivo. - Quando il sistema chiama il tuo metodo di callback
onServiceConnected()
, puoi iniziare a effettuare chiamate al servizio utilizzando i metodi definiti dall'interfaccia. - Per disconnetterti dal servizio, chiama il numero
unbindService()
.Se il client è ancora associato a un servizio quando l'app elimina il client, l'eliminazione provoca la disconnessione del client. È consigliabile svincolare il client non appena ha terminato l'interazione con il servizio. In questo modo il servizio inattivo verrà arrestato. Per ulteriori informazioni sui momenti appropriati per eseguire l'associazione e lo svincolo, consulta la sezione Note aggiuntive.
L'esempio seguente connette il client al servizio creato in precedenza estendendo la classe Binder, quindi non deve fare altro che eseguire il cast dell'elemento IBinder
restituito alla classe LocalBinder
e richiedere l'istanza LocalService
:
Kotlin
var mService: LocalService 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") 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"); mBound = false; } };
Con questo ServiceConnection
, il client può associarsi a un servizio passandolo a bindService()
, come mostrato nell'esempio seguente:
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);
- Il primo parametro di
bindService()
è unIntent
che denomina esplicitamente il servizio da associare.Attenzione: se utilizzi un intent per eseguire l'associazione a un
Service
, assicurati che la tua app sia sicura utilizzando un intent esplicito. L'utilizzo di un intent implicito per avviare un servizio rappresenta un rischio per la sicurezza perché non puoi sapere quale servizio risponda all'intent e l'utente non può vedere quale servizio viene avviato. A partire da Android 5.0 (livello API 21), il sistema genera un'eccezione se chiamibindService()
con un intent implicito. - Il secondo parametro è l'oggetto
ServiceConnection
. - Il terzo parametro è un flag che indica le opzioni per l'associazione, di solito
BIND_AUTO_CREATE
, per creare il servizio, se non è già attivo. Altri valori possibili sonoBIND_DEBUG_UNBIND
,BIND_NOT_FOREGROUND
o0
per nessuno.
Note aggiuntive
Di seguito sono riportate alcune note importanti sull'associazione a un servizio:
- Blocca sempre le eccezioni
DeadObjectException
, che vengono generate quando la connessione si interrompe. Questa è l'unica eccezione generata dai metodi remoti. - Gli oggetti vengono conteggiati come riferimento nei processi.
- In genere devi associare e annullare l'associazione durante i momenti di attivazione e rimozione corrispondenti del ciclo di vita del client, come descritto nei seguenti esempi:
- Se devi interagire con il servizio solo mentre la tua attività è visibile, esegui il binding durante
onStart()
e svincola duranteonStop()
. - Se vuoi che l'attività riceva risposte anche quando è interrotta in background, esegui un collegamento durante
onCreate()
e svincola duranteonDestroy()
. Tieni presente che ciò implica che la tua attività deve utilizzare il servizio per tutto il tempo in cui è in esecuzione, anche in background. Di conseguenza, quando il servizio si trova in un altro processo, il peso del processo aumenta ed è più probabile che venga interrotto dal sistema.
Nota: in genere non devi vincolare e svincolare durante i callback
onResume()
eonPause()
dell'attività, perché questi callback vengono eseguiti a ogni transizione del ciclo di vita. Limita al minimo l'elaborazione che avviene in corrispondenza di queste transizioni.Inoltre, se più attività nella tua applicazione si associano allo stesso servizio e si verifica una transizione tra due di queste attività, il servizio potrebbe essere eliminato e ricreato quando l'attività corrente si svincola (durante la pausa) prima dell'associazione di quella successiva (durante il ripristino). Il modo in cui le attività coordinano i loro cicli di vita è descritto in Il ciclo di vita delle attività.
- Se devi interagire con il servizio solo mentre la tua attività è visibile, esegui il binding durante
Per ulteriore codice di esempio che mostra come eseguire l'associazione a un servizio, consulta la classe
RemoteService.java
in ApiDemos.
Gestisci il ciclo di vita di un servizio associato
Quando un servizio non è associato a tutti i client, il sistema Android lo elimina
(a meno che non sia stato avviato utilizzando
startService()
).
In questo modo, non devi gestire il ciclo di vita del tuo servizio se è puramente un servizio associato. Il sistema Android lo gestisce per te
a seconda che sia vincolato a client.
Tuttavia, se scegli di implementare il metodo di callback onStartCommand()
, devi interrompere esplicitamente il servizio poiché ora il servizio viene considerato avviato. In questo caso, il servizio rimane in esecuzione finché non si arresta con stopSelf()
o un altro componente chiama stopService()
, a prescindere dal fatto che sia associato a un client.
Inoltre, se il servizio è stato avviato e accetta l'associazione, quando il sistema chiama il tuo metodo onUnbind()
, puoi facoltativamente restituire true
se vuoi ricevere una chiamata a onRebind()
la prossima volta che un client si associa al servizio. onRebind()
restituisce void, ma il client riceve comunque IBinder
nel callback onServiceConnected()
.
La figura seguente illustra la logica di questo tipo di ciclo di vita.
Per saperne di più sul ciclo di vita di un servizio avviato, vedi la panoramica dei servizi.