Panoramica dei servizi

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 a stopSelf() o stopService(). 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 valore IBinder. 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() o onBind()). 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 chiama onStartCommand(), ma non ricaricare l'ultimo intent. Il sistema chiama invece onStartCommand() 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 chiama onStartCommand() 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 chiamando stopSelf(). Un altro componente può anche interrompere chiamando il numero stopService(). 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'interfaccia IBinder. Il client può chiudere la connessione chiamando unbindService(). È 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 fun onCreate() {
        // The service is being created
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // The service is starting, due to a call to startService()
        return startMode
    }

    override fun onBind(intent: Intent): IBinder? {
        // A client is binding to the service with bindService()
        return binder
    }

    override fun onUnbind(intent: Intent): Boolean {
        // All clients have unbound with unbindService()
        return allowRebind
    }

    override fun onRebind(intent: Intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }

    override fun onDestroy() {
        // The service is no longer used and is being destroyed
    }
}

Java

public class ExampleService extends Service {
    int startMode;       // indicates how to behave if the service is killed
    IBinder binder;      // interface for clients that bind
    boolean allowRebind; // indicates whether onRebind should be used

    @Override
    public void onCreate() {
        // The service is being created
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // The service is starting, due to a call to startService()
        return startMode;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // A client is binding to the service with bindService()
        return binder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        // All clients have unbound with unbindService()
        return allowRebind;
    }
    @Override
    public void onRebind(Intent intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }
    @Override
    public void onDestroy() {
        // 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.

Figura 2. Il ciclo di vita del servizio. Il diagramma a sinistra mostra il ciclo di vita in cui il servizio viene creato con startService() e il diagramma a destra mostra il ciclo di vita in cui viene creato il servizio con bindService().

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 restituito onDestroy(). Come un'attività, un servizio esegue la configurazione iniziale in onCreate() e rilascia tutte le risorse rimanenti in onDestroy(). Ad esempio, un Il servizio di riproduzione di musica può creare il thread in cui la musica viene riprodotta in onCreate() e poi interrompere il thread in onDestroy().

    Nota: onCreate() e onDestroy() vengono richiamati per tutti i servizi, vengono creati da startService() o bindService().

  • La durata attiva di un servizio inizia con una chiamata a onStartCommand() o onBind(). A ogni metodo viene inviato il Intent passato a startService() o bindService().

    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 di onUnbind().

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.