Un Service
è un
componente dell'applicazione in grado di eseguire
le operazioni a lunga esecuzione in background. Non fornisce un'interfaccia utente. Una volta
un servizio potrebbe continuare a rimanere in esecuzione per un certo periodo di tempo, anche dopo che l'utente è passato a un altro
un'applicazione. Inoltre, un componente può essere associato a un servizio per interagire con quest'ultimo e persino
comunicazione tra processi (IPC, Inter-Process Communication). Ad esempio, un servizio può gestire le transazioni di rete,
musica, eseguire l'I/O dei file o interagire con un fornitore di contenuti, il tutto in background.
Attenzione:un servizio viene eseguito nel thread principale del rispettivo servizio di hosting processo; Il servizio non crea il proprio thread e non vengano eseguiti in un processo separato, se non diversamente specificato. Devi eseguire eventuali operazioni di blocco un thread separato all'interno del servizio per evitare l'applicazione Errori ANR (Non risposta).
Tipi di servizi
Ecco i tre diversi tipi di servizi:
- Primo piano
-
Un servizio in primo piano esegue un'operazione notevole utente. Ad esempio, un'app audio utilizza un servizio in primo piano per riprodurre un traccia audio. Per i servizi in primo piano deve essere visualizzata una Notifica. I servizi in primo piano continuano a essere eseguiti anche quando l'utente non interagisce con l'app.
Quando utilizzi un servizio in primo piano, devi visualizzare una notifica in modo che gli utenti sono attivamente consapevoli che il servizio è in esecuzione. Questa notifica non può verrà ignorato, a meno che il servizio non venga interrotto o rimosso in primo piano.
Scopri di più su come configurare servizi in primo piano nel tuo dell'app.
Nota: la L'API WorkManager offre un modo flessibile per pianificare le attività ed è in grado di eseguire questi job come servizi in primo piano, se necessario. In molti casi, l'utilizzo È preferibile utilizzare i servizi in primo piano direttamente in WorkManager.
- Premessa
- Un servizio in background esegue un'operazione che non viene rilevata direttamente dal
per l'utente. Ad esempio, se un'app usava un servizio per compattare lo spazio di archiviazione,
che solitamente è un servizio in background.
Nota:se la tua app ha come target il livello API 26 o versioni successive, il sistema impone limitazioni sull'esecuzione in background quando l'app stessa non è in primo piano. Nella maggior parte dei casi, Ad esempio, non dovresti di accedere alle informazioni sulla posizione lo sfondo. Invece, pianificare le attività con WorkManager.
- Associato
- Un servizio è associato quando un componente dell'applicazione si associa ad esso chiamando
bindService()
. Un servizio associato offre un client-server che consente ai componenti di interagire con il servizio, inviare richieste, ricevere e lo fanno in tutti i processi grazie alla comunicazione tra processi (IPC, Inter-Process Communication). Viene eseguito solo un servizio associato purché sia associato un altro componente dell'applicazione. Più componenti possono essere associati contemporaneamente, ma quando tutti vengono slegati, il servizio viene eliminato.
Anche se questa documentazione generalmente illustra separatamente i servizi avviati e associati,
il tuo servizio può funzionare in entrambi i modi: può essere avviato (per essere eseguito a tempo indeterminato) e consentire anche
associazione. Il problema è semplicemente quello di implementare o meno un paio di metodi di callback: onStartCommand()
per consentire ai componenti di avviarlo e onBind()
per consentire l'associazione.
Indipendentemente dal fatto che il servizio sia stato avviato, vincolato o entrambi, qualsiasi componente dell'applicazione
possono usare il servizio (anche da un'applicazione separata) nello stesso modo in cui può usare qualsiasi componente
un'attività, iniziando con un Intent
. Tuttavia, puoi dichiarare
il servizio impostandolo su private nel file manifest e blocca l'accesso da altre applicazioni.
Questo argomento verrà discusso più in dettaglio nella sezione relativa alla dichiarazione del servizio nel
del file manifest.
Scegliere tra un servizio e un thread
Un servizio è semplicemente un componente che può essere eseguito in background, anche quando l'utente non che interagisce con la tua applicazione, quindi dovresti creare un servizio solo se è questo necessaria.
Se devi eseguire operazioni al di fuori del thread principale, ma solo mentre l'utente sta interagendo
con la tua applicazione, devi invece creare un nuovo thread nel contesto di un'altra applicazione
di strumento di authoring. Ad esempio, se vuoi ascoltare un po' di musica, ma solo mentre l'attività è in esecuzione,
potresti creare un thread in onCreate()
,
inizia a eseguirlo in onStart()
,
e lo interrompi in onStop()
.
Considera anche l'utilizzo di pool di thread ed esecutori del pacchetto java.util.concurrent
o coroutine di Kotlin al posto delle
Thread
corso. Consulta le
Documento Threading su Android per ulteriori informazioni su
e trasferire l'esecuzione nei thread in background.
Ricorda che se utilizzi un servizio, questo viene comunque eseguito nel thread principale della tua applicazione predefinita, quindi devi comunque creare un nuovo thread all'interno del servizio se quest'ultimo è intensivo delle operazioni di blocco.
Nozioni di base
Per creare un servizio, devi creare una sottoclasse Service
o utilizzarne una
delle sue sottoclassi esistenti. Nella tua implementazione, devi sostituire alcuni metodi di callback che
gestire gli aspetti chiave del ciclo di vita del servizio e fornire un meccanismo che consenta ai componenti di
per l'associazione al servizio, se opportuno. Questi sono i metodi di callback più importanti che dovresti
override:
onStartCommand()
- Il sistema richiama questo metodo chiamando
startService()
quando un altro componente (ad esempio un'attività) richiede l'avvio del servizio. Quando questo metodo viene eseguito, il servizio viene avviato e può essere eseguito background a tempo indeterminato. Se lo implementi, è tua responsabilità interrompere il servizio quando completa la chiamata astopSelf()
ostopService()
. Se vuoi fornire solo l'associazione, non devi per implementare questo metodo. onBind()
- Il sistema richiama questo metodo chiamando
bindService()
quando un altro componente vuole collegarsi al servizio (ad esempio per eseguire RPC). Nell'implementazione di questo metodo, devi fornire un'interfaccia che i clienti per comunicare con il servizio restituendo un valoreIBinder
. Devi sempre implementare questo metodo; Tuttavia, se non vuoi consentire l'associazione, devi restituire null. onCreate()
- Il sistema richiama questo metodo per eseguire procedure di configurazione una tantum quando il servizio
creato inizialmente (prima che chiami
onStartCommand()
oonBind()
). Se il servizio è già in esecuzione, questo metodo non viene chiamato. onDestroy()
- Il sistema richiama questo metodo quando il servizio non viene più utilizzato ed è in fase di eliminazione. Il tuo servizio dovrebbe implementarlo per ripulire eventuali risorse come thread, ascoltatori o riceventi. Questa è l'ultima chiamata ricevuta dal servizio.
Se un componente avvia il servizio chiamando startService()
(che determina una chiamata a onStartCommand()
), il servizio
continua a essere eseguito finché non si arresta con stopSelf()
o un altro
lo interrompe chiamando stopService()
.
Se un componente chiama
bindService()
per creare il servizio e onStartCommand()
non viene chiamato, il servizio viene eseguito
solo finché il componente è associato. Una volta che il servizio viene slegato da tutti i suoi client,
il sistema la distrugge.
Il sistema Android interrompe un servizio solo quando la memoria è in esaurimento e deve ripristinare il sistema
e risorse per l'attività incentrata sugli utenti. Se il servizio è associato a un'attività che include
è meno probabile che venga ucciso: Se viene dichiarato che il servizio è eseguito in primo piano, viene interrotto raramente.
Se il servizio viene avviato ed è a lunga esecuzione, il sistema abbassa la sua posizione
nell'elenco delle attività in background nel tempo e il servizio diventa molto suscettibile
interruzione: se il servizio viene avviato, devi progettarlo in modo da gestire agevolmente i riavvii
dal sistema. Se il sistema termina il servizio, lo riavvia appena le risorse
ma dipende anche dal valore restituito da onStartCommand()
. Per ulteriori informazioni
su quando il sistema potrebbe eliminare un servizio, consulta la sezione Processi e Threading
documento.
Nelle sezioni seguenti, viene spiegato come creare
startService()
e
bindService()
metodi di servizio e come utilizzarli
da altri componenti dell'applicazione.
Dichiarazione di un servizio nel file manifest
Devi dichiarare tutti i servizi nel cluster manifest, proprio come fai per le attività e gli altri componenti.
Per dichiarare il tuo servizio, aggiungi un elemento <service>
come figlio di <application>
. Ecco un esempio:
<manifest ... > ... <application ... > <service android:name=".ExampleService" /> ... </application> </manifest>
Visualizza l'elemento <service>
riferimento per ulteriori informazioni sulla dichiarazione del servizio nel file manifest.
Esistono altri attributi che puoi includere nell'elemento <service>
per
definiscono proprietà quali le autorizzazioni necessarie per avviare il servizio e il processo
che il servizio deve eseguire. La android:name
è l'unico attributo obbligatorio: specifica il nome della classe del servizio. Dopo il giorno
pubblichi la tua applicazione, non modificare questo nome per evitare il rischio
a causa della dipendenza da intenti espliciti per avviare o associare il servizio (leggi il post del blog, Things
che non può cambiare).
Attenzione: per assicurarti che la tua app sia sicura, usa sempre
l'intent esplicito all'avvio di un Service
e non dichiarare i filtri per intent per
i tuoi servizi. L'utilizzo di un intento implicito per avviare un servizio è un rischio per la sicurezza perché non è possibile
essere certo del servizio che risponde all'intento e l'utente non possa vedere quale servizio
. A partire da Android 5.0 (livello API 21), il sistema genera un'eccezione se chiami
bindService()
con un intent implicito.
Per assicurarti che il servizio sia disponibile solo per la tua app
incluso android:exported
e impostandolo su false
. In questo modo, altre app non possono avviare
servizio, anche quando si utilizza un intento esplicito.
Nota:
Gli utenti possono vedere quali servizi sono in esecuzione sul loro dispositivo. Se vede
un servizio che non riconoscono o non considerano attendibili, possono interromperlo. Nella
per evitare che il servizio venga interrotto accidentalmente dagli utenti, devi
per aggiungere
android:description
all'attributo
<service>
nel file manifest dell'app. Nella descrizione,
fornire una breve frase che spieghi cosa fa il servizio e quali vantaggi
che fornisce.
Creazione di un servizio avviato
Un servizio avviato è un servizio che viene avviato da un altro componente chiamando startService()
, che determina una chiamata al servizio
Metodo onStartCommand()
.
Quando un servizio viene avviato, ha un ciclo di vita indipendente
componente che l'ha avviato. Il servizio può essere eseguito in background a tempo indeterminato, anche se
il componente che lo ha avviato viene eliminato. Di conseguenza, il servizio dovrebbe arrestarsi quando il suo job
viene completata chiamando stopSelf()
, oppure un altro componente può
puoi interromperlo chiamando il numero stopService()
.
Un componente dell'applicazione come un'attività può avviare il servizio chiamando startService()
e trasmettendo un Intent
che specifica il servizio e include tutti i dati che il servizio può utilizzare. Il servizio riceve
questo Intent
nel metodo onStartCommand()
.
Ad esempio, supponiamo che un'attività debba salvare alcuni dati in un database online. L'attività
può avviare un servizio companion e inviare i dati da salvare trasmettendo un intent a startService()
. Il servizio riceve l'intent in onStartCommand()
, si connette a internet ed esegue
una transazione di database. Al completamento della transazione, il servizio si interrompe automaticamente
distrutte.
Attenzione:un servizio viene eseguito nello stesso processo dell'applicazione in cui viene dichiarato e nel thread principale dell'applicazione per impostazione predefinita. Se il tuo servizio esegue operazioni intense o di blocco mentre l’utente interagisce con un’attività dello stesso applicazione, il servizio rallenta le prestazioni dell'attività. Per evitare ripercussioni sull'applicazione delle prestazioni, avvia un nuovo thread all'interno del servizio.
La classe Service
è la base
per tutti i servizi. Quando estendi questo corso, è importante creare un nuovo thread in cui
il servizio possa completare tutto il suo lavoro; il servizio utilizza il thread principale della tua applicazione
predefinito, che può rallentare le prestazioni di qualsiasi attività in esecuzione sull'applicazione.
Il framework Android fornisce inoltre IntentService
una sottoclasse di Service
che utilizza un
il thread di worker per gestire tutte le richieste di avvio, una alla volta. L'utilizzo di questo corso non è consentito
consigliato per le nuove app, in quanto non funzionerà bene a partire da Android 8 Oreo a causa del
introduzione dei limiti di esecuzione in background.
Inoltre, è stata ritirata a partire da Android 11.
Puoi utilizzare JobIntentService come
sostituzione di IntentService
compatibile con le versioni più recenti di Android.
Le seguenti sezioni descrivono come implementare un servizio personalizzato, ma dovresti valuta l'utilizzo di WorkManager nella maggior parte dei casi d'uso. Consulta la guida all'elaborazione in background su Android per scoprire se esiste una soluzione adatta alle tue esigenze.
Estensione della classe Service
Puoi estendere il corso Service
per gestire ogni intenzione in arrivo. Ecco come potrebbe apparire un'implementazione di 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(); } }
Il codice di esempio gestisce tutte le chiamate in arrivo in onStartCommand()
e pubblica il lavoro in una Handler
in esecuzione su un thread in background. Funziona proprio come un IntentService
ed elabora tutte le richieste in modo seriale, una dopo l'altra.
Puoi modificare il codice in modo che esegua il lavoro su un pool di thread, ad esempio se vuoi eseguire più richieste contemporaneamente.
Tieni presente che il metodo onStartCommand()
deve restituire un
numero intero. Il numero intero è un valore che descrive in che modo il sistema deve continuare il servizio nel
evento in cui il sistema lo termina. Il valore restituito
da onStartCommand()
deve essere uno dei seguenti
costanti:
START_NOT_STICKY
- Se il sistema termina il servizio dopo il ritorno di
onStartCommand()
, non ricreare il servizio a meno che non siano in sospeso gli intenti da consegnare. Questa è l'opzione più sicura per evitare di eseguire il servizio quando non è necessario e quando l'applicazione può semplicemente riavviare i lavori non completati. START_STICKY
- Se il sistema termina il servizio dopo il ritorno di
onStartCommand()
, ricrea il servizio e chiamaonStartCommand()
, ma non ricaricare l'ultimo intent. Il sistema chiama inveceonStartCommand()
con un intent nullo, a meno che non siano presenti intent in attesa per avviare il servizio. In questo caso, per realizzarli. È adatto a lettori multimediali (o servizi simili) che non sono ma che vengono eseguiti all'infinito e in attesa di un job. START_REDELIVER_INTENT
- Se il sistema termina il servizio dopo il ritorno di
onStartCommand()
, ricrea il servizio e chiamaonStartCommand()
con l'ultimo intent consegnato al completamente gestito di Google Cloud. Eventuali intent in attesa vengono pubblicati a rotazione. È adatto ai servizi che sono eseguendo attivamente un lavoro che dovrebbe essere immediatamente ripreso, come il download di un file.
Per ulteriori dettagli su questi valori restituiti, consulta il riferimento collegato documentazione per ogni costante.
Avvio di un servizio
Puoi avviare un servizio da un'attività o da un altro componente dell'applicazione
passando un Intent
a startService()
o startForegroundService()
. La
Il sistema Android chiama il metodo onStartCommand()
del servizio e gli passa Intent
,
che specifica quale servizio avviare.
Nota: se la tua app ha come target il livello API 26 o versioni successive, il sistema
impone limitazioni sull'utilizzo o sulla creazione di servizi in background, a meno che l'app
stessa è in primo piano. Se un'app deve creare un servizio in primo piano,
l'app dovrebbe chiamare startForegroundService()
. Questo metodo crea un servizio in background, ma
segnala al sistema che il servizio si promuoverà
in primo piano. Una volta creato, il servizio deve chiamare la sua
startForeground()
metodo in
cinque secondi.
Ad esempio, un'attività può avviare il servizio di esempio nella sezione precedente (HelloService
) utilizzando un intent esplicito con startService()
, come mostrato qui:
Kotlin
startService(Intent(this, HelloService::class.java))
Java
startService(new Intent(this, HelloService.class));
Il metodo startService()
restituisce immediatamente e
il sistema Android chiama il metodo onStartCommand()
del servizio. Se il servizio non è già in esecuzione, il sistema prima chiama onCreate()
, poi chiama
onStartCommand()
.
Se il servizio non fornisce anche l'associazione, l'intent fornito con startService()
è l'unica modalità di comunicazione tra il
dell'applicazione e il servizio. Se invece vuoi che il servizio restituisca un risultato,
il client che avvia il servizio può creare un PendingIntent
per una trasmissione
(con getBroadcast()
) e la consegna al servizio
nel Intent
che avvia il servizio. Il servizio può quindi utilizzare
per ottenere un risultato.
Più richieste di avvio del servizio generano più chiamate corrispondenti al servizio
onStartCommand()
. Tuttavia, esiste una sola richiesta di interruzione
è necessario il servizio (con stopSelf()
o stopService()
) per arrestarlo.
Arresto di un servizio
Un servizio avviato deve gestire il proprio ciclo di vita. In altre parole, il sistema non si arresta
eliminare il servizio a meno che non debba recuperare la memoria di sistema e il servizio
continua a essere eseguita dopo il ritorno di onStartCommand()
. La
il servizio deve interrompersi chiamando stopSelf()
o un altro
può interromperlo chiamando stopService()
.
Dopo aver richiesto l'interruzione con stopSelf()
o stopService()
, il sistema distrugge il servizio non appena
possibile.
Se il tuo servizio gestisce più richieste a onStartCommand()
contemporaneamente, non devi interrompere
quando hai terminato di elaborare una richiesta di avvio, in quanto potresti aver ricevuto
iniziale (l'interruzione al termine della prima richiesta comporta la terminazione della seconda). Da evitare
questo problema, puoi utilizzare stopSelf(int)
per assicurarti che la tua richiesta
l'interruzione del servizio si basa sempre sulla richiesta di avvio più recente. In altre parole, quando chiami stopSelf(int)
, passi l'ID della richiesta di avvio (il startId
consegnato a onStartCommand()
) a cui hai inviato la richiesta di interruzione
corrisponde a quello originale. Quindi, se il servizio riceve una nuova richiesta di avvio prima che tu possa chiamare stopSelf(int)
, l'ID non corrisponde e il servizio non viene interrotto.
Attenzione:per evitare di sprecare risorse di sistema e di consumare
carica della batteria, assicurati che l'applicazione interrompa i servizi quando ha finito di funzionare.
Se necessario, altri componenti possono interrompere il servizio chiamando il numero stopService()
. Anche se abiliti l'associazione per il servizio,
devi sempre interrompere il servizio autonomamente nel caso in cui riceva una chiamata al numero onStartCommand()
.
Per saperne di più sul ciclo di vita di un servizio, consulta la sezione Gestione del ciclo di vita di un servizio riportata di seguito.
Creazione di un servizio associato
Un servizio associato consente ai componenti dell'applicazione di associarsi al servizio chiamando bindService()
per creare una connessione di lunga data.
In genere non consente ai componenti di avviarlo chiamando il numero startService()
.
Crea un servizio associato quando vuoi interagire con il servizio dalle attività e altri componenti della tua applicazione o per esporre alcune delle funzionalità dell'applicazione altre applicazioni attraverso la comunicazione inter-process (IPC).
Per creare un servizio associato, implementa il metodo di callback onBind()
per restituire un valore IBinder
che
definisce l'interfaccia di comunicazione con il servizio. Gli altri componenti dell'applicazione possono quindi chiamare
bindService()
per recuperare l'interfaccia e
per iniziare a chiamare metodi sul servizio. Il servizio risiede solo per gestire il componente dell'applicazione
e quindi, quando non ci sono componenti associati al servizio, il sistema lo distrugge.
Non è necessario arrestare un servizio associato come faresti quando il servizio viene
avviato fino al giorno onStartCommand()
.
Per creare un servizio associato, devi definire l'interfaccia che specifica in che modo un client può
comunicare con il servizio. Questa interfaccia
e un client deve essere un'implementazione di IBinder
ed è ciò che il tuo servizio deve
dal metodo di callback onBind()
. Dopo che il client ha ricevuto IBinder
, può iniziare
a interagire con il servizio
tramite quell'interfaccia.
È possibile associare più client al servizio contemporaneamente. Quando un cliente ha finito di interagire
al servizio, chiama unbindService()
per lo slegamento.
Se al servizio non è associato alcun client, il sistema lo elimina.
Esistono diversi modi per implementare un servizio associato e l'implementazione è complicato di un servizio iniziato. Per questi motivi, la discussione del servizio associato viene visualizzata in documento separato sui Servizi associati.
Invio di notifiche all'utente
Quando un servizio è in esecuzione, può informare l'utente degli eventi utilizzando le notifiche dello snackbar o le notifiche della barra di stato.
Una notifica snackbar è un messaggio che viene visualizzato nella superficie della finestra corrente solo per un un istante prima di scomparire. Una notifica nella barra di stato fornisce un'icona nella barra di stato con un che l'utente può selezionare per eseguire un'azione (ad esempio, avviare un'attività).
Di solito, una notifica nella barra di stato è la tecnica migliore da utilizzare quando lavori in background, come il download di un file è terminato e l'utente può intervenire sul file. Quando l'utente seleziona la notifica dalla visualizzazione espansa, la notifica può avviare un'attività (ad esempio per visualizzare il file scaricato).
Gestione del ciclo di vita di un servizio
Il ciclo di vita di un servizio è molto più semplice di quello di un'attività. Tuttavia, è ancora più è importante prestare particolare attenzione al modo in cui il servizio viene creato ed eliminato, può essere eseguito in background all'insaputa dell'utente.
Il ciclo di vita dei servizi, da quando viene creato a quando viene eliminato, può seguire uno di questi due percorsi:
- Un servizio avviato
Il servizio viene creato quando un altro componente chiama
startService()
. Il servizio viene quindi eseguito a tempo indeterminato e deve interrompi la chiamata chiamandostopSelf()
. Un altro componente può anche interrompere chiamando il numerostopService()
. Quando il servizio viene interrotto, il sistema lo distrugge. - Un servizio associato
Il servizio viene creato quando un altro componente (un client) chiama
bindService()
. Il client comunica quindi con il servizio tramite un'interfacciaIBinder
. Il client può chiudere la connessione chiamandounbindService()
. È possibile eseguire l'associazione a più client lo stesso servizio e, quando vengono svincolati tutti, il sistema distrugge il servizio. Il servizio non si deve fermare.
Questi due percorsi non sono completamente separati. Puoi eseguire l'associazione a un servizio già esistente
iniziato con startService()
. Ad esempio, puoi
avvia un servizio di musica di sottofondo chiamando startService()
con un Intent
che identifica la musica da riprodurre. Più tardi,
magari quando l'utente vuole esercitare un certo controllo sul player o ottenere informazioni
brano corrente, un'attività può associarsi al servizio chiamando bindService()
. In questi casi, stopService()
o stopSelf()
non interrompe il servizio fino a quando tutti i client non svincono l'associazione.
Implementazione dei callback del ciclo di vita
Come un'attività, un servizio ha metodi di callback del ciclo di vita che puoi implementare per monitorare modifiche allo stato del servizio ed eseguire il lavoro al momento giusto. Lo scheletro seguente del servizio illustra ciascuno dei metodi del ciclo di vita:
Kotlin
class ExampleService : Service() { private var startMode: Int = 0 // indicates how to behave if the service is killed private var binder: IBinder? = null // interface for clients that bind private var allowRebind: Boolean = false // indicates whether onRebind should be used override funonCreate
() { // The service is being created } override funonStartCommand
(intent: Intent?, flags: Int, startId: Int): Int { // The service is starting, due to a call to startService() return startMode } override funonBind
(intent: Intent): IBinder? { // A client is binding to the service with bindService() return binder } override funonUnbind
(intent: Intent): Boolean { // All clients have unbound with unbindService() return allowRebind } override funonRebind
(intent: Intent) { // A client is binding to the service with bindService(), // after onUnbind() has already been called } override funonDestroy
() { // The service is no longer used and is being destroyed } }
Java
public class ExampleService extends Service { int startMode; // indicates how to behave if the service is killed IBinder binder; // interface for clients that bind boolean allowRebind; // indicates whether onRebind should be used @Override public voidonCreate
() { // The service is being created } @Override public intonStartCommand
(Intent intent, int flags, int startId) { // The service is starting, due to a call tostartService()
return startMode; } @Override public IBinderonBind
(Intent intent) { // A client is binding to the service withbindService()
return binder; } @Override public booleanonUnbind
(Intent intent) { // All clients have unbound withunbindService()
return allowRebind; } @Override public voidonRebind
(Intent intent) { // A client is binding to the service withbindService()
, // after onUnbind() has already been called } @Override public voidonDestroy
() { // The service is no longer used and is being destroyed } }
Nota: a differenza dei metodi di callback del ciclo di vita delle attività, non è necessario chiamare l'implementazione della superclasse di questi metodi di callback.
La Figura 2 illustra i tipici metodi di callback per un servizio. Sebbene la figura separa
di servizi creati da startService()
da quelli
creato da bindService()
, mantieni
tieni presente che qualsiasi servizio, indipendentemente da come sia stato avviato, può potenzialmente consentire ai clienti di associarsi ad esso.
Un servizio inizialmente avviato con onStartCommand()
(da un client che chiama startService()
)
può comunque ricevere una chiamata al numero onBind()
(quando un cliente chiama
bindService()
).
Con l'implementazione di questi metodi, puoi monitorare questi due loop nidificati del set di dati ciclo di vita:
- L'intera durata di un servizio si verifica tra il momento in cui viene chiamato
onCreate()
e quello in cui viene restituitoonDestroy()
. Come un'attività, un servizio esegue la configurazione iniziale inonCreate()
e rilascia tutte le risorse rimanenti inonDestroy()
. Ad esempio, un Il servizio di riproduzione di musica può creare il thread in cui la musica viene riprodotta inonCreate()
e poi interrompere il thread inonDestroy()
.Nota:
onCreate()
eonDestroy()
vengono richiamati per tutti i servizi, vengono creati dastartService()
obindService()
. - La durata attiva di un servizio inizia con una chiamata a
onStartCommand()
oonBind()
. A ogni metodo viene inviato ilIntent
passato astartService()
obindService()
.Se il servizio viene avviato, il ciclo di vita attivo termina nello stesso momento in cui l'intera durata (il servizio è ancora attivo anche dopo il reso di
onStartCommand()
). Se il servizio è associato, il ciclo di vita attivo termina al ritorno dionUnbind()
.
Nota: anche se un servizio avviato viene interrotto da una chiamata al
stopSelf()
o stopService()
, non esiste un callback rispettivo per il
(non viene richiamato onStop()
). A meno che il servizio non sia associato a un client,
il sistema la elimina quando il servizio viene arrestato: onDestroy()
è l'unico callback ricevuto.
Per ulteriori informazioni sulla creazione di un servizio che fornisce l'associazione, vedi il documento Bound Services,
che include ulteriori informazioni su onRebind()
di callback di Google nella sezione relativa alla gestione del ciclo di vita
un servizio associato.