Überblick über die Dienste

Eine Service ist eine Anwendungskomponente, die lang andauernde Vorgänge im Hintergrund ausführen kann. Sie bietet keine Benutzeroberfläche. Nach dem Start wird ein Dienst möglicherweise noch einige Zeit weiter ausgeführt, auch wenn der Nutzer zu einer anderen Anwendung gewechselt ist. Darüber hinaus kann eine Komponente an einen Dienst gebunden werden, um mit ihm zu interagieren und sogar eine Interprocess Communication (IPC) durchzuführen. Beispielsweise kann ein Dienst im Hintergrund Netzwerktransaktionen verarbeiten, Musik abspielen, Datei-E/A ausführen oder mit einem Contentanbieter interagieren.

Achtung:Ein Dienst wird im Hauptthread seines Hostingprozesses ausgeführt. Der Dienst erstellt keinen eigenen Thread und wird nicht in einem separaten Prozess ausgeführt, sofern Sie nichts anderes angeben. Sie sollten alle blockierenden Vorgänge in einem separaten Thread innerhalb des Dienstes ausführen, um ANR-Fehler (Application Not Responding) zu vermeiden.

Arten von Dienstleistungen

Es gibt drei verschiedene Arten von Diensten:

Vordergrund

Ein Dienst im Vordergrund führt einen Vorgang aus, der für den Nutzer erkennbar ist. Eine Audio-App würde beispielsweise einen Dienst im Vordergrund zur Wiedergabe eines Audiotracks verwenden. Für Dienste im Vordergrund muss eine Benachrichtigung angezeigt werden. Dienste im Vordergrund werden auch dann weiter ausgeführt, wenn der Nutzer nicht mit der Anwendung interagiert.

Wenn Sie einen Dienst im Vordergrund verwenden, müssen Sie eine Benachrichtigung anzeigen lassen, damit Nutzer aktiv wissen, dass der Dienst ausgeführt wird. Diese Benachrichtigung kann nur geschlossen werden, wenn der Dienst entweder angehalten oder aus dem Vordergrund entfernt wurde.

Weitere Informationen zum Konfigurieren von Diensten im Vordergrund in Ihrer Anwendung.

Hinweis:Die WorkManager API bietet eine flexible Möglichkeit, Aufgaben zu planen. Sie kann diese Jobs bei Bedarf als Dienste im Vordergrund ausführen. In vielen Fällen ist die Verwendung von WorkManager besser als direkt mit Diensten im Vordergrund zu verwenden.

Hintergrund
Ein Hintergrunddienst führt einen Vorgang aus, der vom Nutzer nicht direkt bemerkt wird. Wenn eine Anwendung beispielsweise einen Dienst zum Komprimieren des Speichers verwendet hat, ist dies in der Regel ein Hintergrunddienst.

Hinweis:Wenn deine App auf API-Level 26 oder höher ausgerichtet ist, schränkt das System die Ausführung von Hintergrunddiensten ein, wenn die App selbst nicht im Vordergrund ausgeführt wird. In den meisten Situationen sollten Sie beispielsweise nicht auf Standortinformationen im Hintergrund zugreifen. Aufgaben stattdessen mit WorkManager planen.

Gebunden
Ein Dienst ist gebunden, wenn eine Anwendungskomponente durch Aufrufen von bindService() an ihn gebunden wird. Ein gebundener Dienst bietet eine Client-Server-Schnittstelle, über die Komponenten mit dem Dienst interagieren, Anfragen senden, Ergebnisse empfangen und dies sogar prozessübergreifend mit Interprocess Communication (IPC) tun können. Ein gebundener Dienst wird nur so lange ausgeführt, wie eine andere Anwendungskomponente an ihn gebunden ist. Mehrere Komponenten können gleichzeitig an den Dienst gebunden werden. Wenn die Bindung jedoch alle aufgehoben wird, wird der Dienst gelöscht.

Auch wenn in dieser Dokumentation gestartete und gebundene Dienste im Allgemeinen separat behandelt werden, kann Ihr Dienst in beide Richtungen funktionieren – er kann gestartet werden (für unbegrenzte Ausführung) und auch Bindung zulassen. Es ist lediglich eine Frage, ob Sie einige Callback-Methoden implementieren: onStartCommand(), damit Komponenten starten können, und onBind(), um Bindung zuzulassen.

Unabhängig davon, ob Ihr Dienst gestartet, gebunden oder beides ist, kann jede Anwendungskomponente den Dienst (auch aus einer separaten Anwendung) auf die gleiche Weise verwenden wie jede Komponente eine Aktivität verwenden, indem sie ihn mit einer Intent startet. Sie können den Dienst jedoch in der Manifestdatei als privat deklarieren und den Zugriff anderer Anwendungen blockieren. Weitere Informationen hierzu finden Sie im Abschnitt Dienst im Manifest deklarieren.

Zwischen einem Dienst und einem Thread auswählen

Ein Dienst ist einfach eine Komponente, die auch dann im Hintergrund ausgeführt werden kann, wenn der Nutzer nicht mit Ihrer Anwendung interagiert. Sie sollten einen Dienst daher nur erstellen, wenn Sie ihn benötigen.

Wenn Sie Arbeiten außerhalb Ihres Hauptthreads, aber nur während der Nutzer mit Ihrer Anwendung interagieren müssen, sollten Sie stattdessen einen neuen Thread im Kontext einer anderen Anwendungskomponente erstellen. Wenn Sie beispielsweise Musik abspielen möchten, aber nur während Ihre Aktivität ausgeführt wird, können Sie einen Thread in onCreate() erstellen, ihn in onStart() starten und in onStop() beenden. Sie können auch Thread-Pools und Executors aus dem java.util.concurrent-Paket oder Kotlin-Coroutinen anstelle der herkömmlichen Thread-Klasse verwenden. Weitere Informationen zum Verschieben der Ausführung in Hintergrundthreads finden Sie im Dokument Threading unter Android.

Wenn Sie einen Dienst verwenden, wird er standardmäßig weiterhin im Hauptthread Ihrer Anwendung ausgeführt. Sie sollten also trotzdem einen neuen Thread innerhalb des Dienstes erstellen, wenn dieser intensive oder blockierende Vorgänge ausführt.

Grundlagen

Zum Erstellen eines Dienstes müssen Sie eine abgeleitete Klasse von Service erstellen oder eine der vorhandenen abgeleiteten Klassen verwenden. In Ihrer Implementierung müssen Sie einige Callback-Methoden überschreiben, die wichtige Aspekte des Dienstlebenszyklus verarbeiten, und einen Mechanismus bereitstellen, mit dem die Komponenten gegebenenfalls an den Dienst gebunden werden können. Dies sind die wichtigsten Callback-Methoden, die Sie überschreiben sollten:

onStartCommand()
Das System ruft diese Methode auf, indem es startService() aufruft, wenn eine andere Komponente (z. B. eine Aktivität) das Starten des Dienstes anfordert. Bei Ausführung dieser Methode wird der Dienst gestartet und kann auf unbestimmte Zeit im Hintergrund ausgeführt werden. Wenn Sie dies implementieren, sind Sie dafür verantwortlich, den Dienst zu beenden, wenn seine Arbeit abgeschlossen ist. Rufen Sie dazu stopSelf() oder stopService() auf. Wenn Sie nur Bindung angeben möchten, müssen Sie diese Methode nicht implementieren.
onBind()
Das System ruft diese Methode auf, indem es bindService() aufruft, wenn eine andere Komponente eine Verbindung mit dem Dienst herstellen möchte (z. B. um einen RPC auszuführen). In der Implementierung dieser Methode müssen Sie eine Schnittstelle bereitstellen, über die Clients mit dem Dienst kommunizieren. Dazu wird ein IBinder zurückgegeben. Sie müssen diese Methode immer implementieren. Wenn Sie jedoch Bindungen nicht zulassen möchten, sollte null zurückgegeben werden.
onCreate()
Das System ruft diese Methode auf, um einmalige Einrichtungsverfahren auszuführen, wenn der Dienst neu erstellt wird, bevor entweder onStartCommand() oder onBind() aufgerufen wird. Wenn der Dienst bereits ausgeführt wird, wird diese Methode nicht aufgerufen.
onDestroy()
Das System ruft diese Methode auf, wenn der Dienst nicht mehr verwendet und gelöscht wird. Ihr Dienst sollte dies implementieren, um Ressourcen wie Threads, registrierte Listener oder Empfänger zu bereinigen. Dies ist der letzte Aufruf, den der Dienst empfängt.

Wenn eine Komponente den Dienst durch Aufrufen von startService() startet (was zu einem Aufruf von onStartCommand() führt), wird der Dienst so lange ausgeführt, bis er sich selbst mit stopSelf() beendet oder eine andere Komponente ihn durch Aufrufen von stopService() beendet.

Wenn eine Komponente bindService() zum Erstellen des Dienstes aufruft und onStartCommand() nicht aufgerufen wird, wird der Dienst nur so lange ausgeführt, wie die Komponente an ihn gebunden ist. Nachdem die Bindung des Dienstes an alle seine Clients aufgehoben wurde, löscht das System ihn.

Das Android-System stoppt einen Dienst nur, wenn nur noch wenig Arbeitsspeicher zur Verfügung steht, und es müssen Systemressourcen für die Aktivität wiederhergestellt werden, die auf den Nutzer ausgerichtet ist. Ist der Dienst an eine Aktivität gebunden, die auf den Nutzer ausgerichtet ist, ist es weniger wahrscheinlich, dass er beendet wird. Ist der Dienst für die Ausführung im Vordergrund deklariert, wird er selten beendet. Wenn der Dienst gestartet wird und lange ausgeführt wird, verschlechtert sich seine Position in der Liste der Hintergrundaufgaben mit der Zeit. Der Dienst ist dann sehr anfällig für Beendigungen. Wenn Ihr Dienst gestartet wird, müssen Sie ihn so konzipieren, dass Neustarts durch das System reibungslos bewältigt werden können. Wenn das System Ihren Dienst beendet, wird es neu gestartet, sobald Ressourcen verfügbar sind. Dies hängt jedoch auch von dem Wert ab, den Sie von onStartCommand() zurückgeben. Weitere Informationen dazu, wann das System einen Dienst löschen könnte, finden Sie im Dokument Prozesse und Threading.

In den folgenden Abschnitten erfahren Sie, wie Sie die Dienstmethoden startService() und bindService() erstellen und in anderen Anwendungskomponenten verwenden können.

Dienst im Manifest deklarieren

Sie müssen alle Dienste in der Manifestdatei Ihrer App deklarieren, genau wie bei Aktivitäten und anderen Komponenten.

Um Ihren Dienst zu deklarieren, fügen Sie ein <service>-Element als untergeordnetes Element des <application>-Elements hinzu. Hier ein Beispiel:

<manifest ... >
  ...
  <application ... >
      <service android:name=".ExampleService" />
      ...
  </application>
</manifest>

Weitere Informationen zum Deklarieren des Dienstes im Manifest finden Sie in der Referenz zu den Elementen <service>.

Sie können weitere Attribute in das Element <service> aufnehmen, um Attribute zu definieren, z. B. die Berechtigungen, die zum Starten des Dienstes erforderlich sind, oder den Prozess, in dem der Dienst ausgeführt werden soll. Das Attribut android:name ist das einzige erforderliche Attribut und gibt den Klassennamen des Dienstes an. Nachdem Sie Ihre Anwendung veröffentlicht haben, lassen Sie diesen Namen unverändert. Andernfalls besteht die Gefahr, dass Code aufgrund von expliziten Intents gestartet oder verknüpft wird, um den Dienst zu starten oder zu binden. Weitere Informationen dazu finden Sie im Blogpost Things, That’s Nicht ändern kann.

Achtung: Damit Ihre Anwendung sicher ist, sollten Sie beim Starten von Service immer einen expliziten Intent verwenden und keine Intent-Filter für Ihre Dienste deklarieren. Die Verwendung eines impliziten Intents zum Starten eines Dienstes stellt ein Sicherheitsrisiko dar, da Sie nicht sicher sein können, welcher Dienst auf den Intent reagiert. Außerdem können Nutzer nicht sehen, welcher Dienst gestartet wird. Ab Android 5.0 (API-Ebene 21) gibt das System eine Ausnahme aus, wenn du bindService() mit einem impliziten Intent aufrufst.

Damit der Dienst nur für Ihre Anwendung verfügbar ist, fügen Sie das Attribut android:exported hinzu und setzen es auf false. Dadurch wird verhindert, dass andere Anwendungen Ihren Dienst starten, selbst wenn ein expliziter Intent verwendet wird.

Hinweis: Nutzer können sehen, welche Dienste auf ihrem Gerät ausgeführt werden. Wenn sie einen Dienst sehen, den sie nicht kennen oder dem sie nicht vertrauen, können sie ihn beenden. Damit dein Dienst nicht versehentlich von Nutzern beendet wird, musst du dem Element <service> in deinem App-Manifest das Attribut android:description hinzufügen. Erläutern Sie in der Beschreibung in einem kurzen Satz, was die Dienstleistung bietet und welche Vorteile sie bietet.

Gestarteten Dienst erstellen

Ein gestarteter Dienst ist ein Dienst, den eine andere Komponente durch Aufrufen von startService() startet. Dies führt zu einem Aufruf der Methode onStartCommand() des Dienstes.

Wenn ein Dienst gestartet wird, hat er einen Lebenszyklus, der unabhängig von der Komponente ist, die ihn gestartet hat. Der Dienst kann auf unbestimmte Zeit im Hintergrund ausgeführt werden, auch wenn die Komponente, die ihn gestartet hat, gelöscht wird. Der Dienst sollte sich also selbst beenden, wenn sein Job abgeschlossen ist, indem stopSelf() aufgerufen wird, oder eine andere Komponente kann ihn durch Aufrufen von stopService() beenden.

Eine Anwendungskomponente wie eine Aktivität kann den Dienst starten, indem sie startService() aufruft und ein Intent-Element übergibt, das den Dienst angibt und alle Daten enthält, die der Dienst verwenden soll. Der Dienst empfängt diese Intent in der Methode onStartCommand().

Angenommen, eine Aktivität muss Daten in einer Online-Datenbank speichern. Die Aktivität kann einen Companion-Dienst starten und ihm die zu speichernden Daten liefern, indem ein Intent an startService() übergeben wird. Der Dienst empfängt den Intent in onStartCommand(), stellt eine Verbindung zum Internet her und führt die Datenbanktransaktion aus. Wenn die Transaktion abgeschlossen ist, beendet der Dienst sich selbst und wird gelöscht.

Achtung:Ein Dienst wird standardmäßig im selben Prozess wie die Anwendung, in der er deklariert ist, und im Hauptthread dieser Anwendung ausgeführt. Wenn Ihr Dienst intensive oder blockierende Vorgänge ausführt, während der Nutzer mit einer Aktivität aus derselben Anwendung interagiert, verlangsamt der Dienst die Aktivitätsleistung. Starten Sie einen neuen Thread innerhalb des Dienstes, um die Anwendungsleistung nicht zu beeinträchtigen.

Die Service-Klasse ist die Basisklasse für alle Dienste. Wenn Sie diese Klasse erweitern, ist es wichtig, einen neuen Thread zu erstellen, in dem der Dienst seine gesamte Arbeit erledigen kann. Der Dienst verwendet standardmäßig den Hauptthread Ihrer Anwendung, was die Leistung aller Aktivitäten Ihrer Anwendung verlangsamen kann.

Das Android-Framework stellt auch die Unterklasse IntentService von Service bereit, die einen Worker-Thread verwendet, um alle Startanfragen nacheinander zu verarbeiten. Die Verwendung dieser Klasse wird für neue Apps nicht empfohlen, da sie ab Android 8 Oreo aufgrund der Einführung von Limits für die Ausführung im Hintergrund nicht gut funktioniert. Außerdem wird sie ab Android 11 eingestellt. Sie können JobIntentService als Ersatz für IntentService verwenden, der mit neueren Android-Versionen kompatibel ist.

In den folgenden Abschnitten wird beschrieben, wie Sie Ihren eigenen benutzerdefinierten Dienst implementieren können. Für die meisten Anwendungsfälle ist es jedoch ratsam, stattdessen WorkManager zu verwenden. Lies den Leitfaden zur Hintergrundverarbeitung unter Android, um herauszufinden, ob es eine Lösung gibt, die deinen Anforderungen entspricht.

Dienstklasse erweitern

Sie können die Klasse Service erweitern, um jeden eingehenden Intent zu verarbeiten. Eine einfache Implementierung könnte so aussehen:

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();
  }
}

Der Beispielcode verarbeitet alle eingehenden Aufrufe in onStartCommand() und sendet die Arbeit an einen Handler, der in einem Hintergrundthread ausgeführt wird. Er funktioniert wie ein IntentService und verarbeitet alle Anfragen nacheinander und nacheinander. Sie können den Code ändern, um die Arbeit an einem Thread-Pool auszuführen, z. B. wenn Sie mehrere Anfragen gleichzeitig ausführen möchten.

Die Methode onStartCommand() muss eine Ganzzahl zurückgeben. Die Ganzzahl ist ein Wert, der beschreibt, wie das System den Dienst fortsetzen soll, wenn das System ihn beendet. Der Rückgabewert von onStartCommand() muss eine der folgenden Konstanten sein:

START_NOT_STICKY
Wenn das System den Dienst beendet, nachdem onStartCommand() zurückgegeben wurde, erstellen Sie den Dienst nicht neu, es sei denn, es sind ausstehende Intents zur Auslieferung vorhanden. Dies ist die sicherste Option, um die Ausführung Ihres Dienstes zu vermeiden, wenn dies nicht erforderlich ist, und wenn Ihre Anwendung einfach alle nicht abgeschlossenen Jobs neu starten kann.
START_STICKY
Wenn das System den Dienst beendet, nachdem onStartCommand() zurückgegeben wurde, erstellen Sie den Dienst neu und rufen Sie onStartCommand() auf. Senden Sie jedoch nicht den letzten Intent noch einmal. Stattdessen ruft das System onStartCommand() mit einem Null-Intent auf, es sei denn, es sind ausstehende Intents zum Starten des Dienstes vorhanden. In diesem Fall werden die Intents zugestellt. Dies eignet sich für Mediaplayer (oder ähnliche Dienste), die keine Befehle ausführen, aber auf unbestimmte Zeit ausgeführt werden und auf einen Job warten.
START_REDELIVER_INTENT
Wenn das System den Dienst beendet, nachdem onStartCommand() zurückgegeben wurde, erstellen Sie den Dienst neu und rufen Sie onStartCommand() mit dem letzten Intent auf, der an den Dienst gesendet wurde. Alle ausstehenden Intents werden nacheinander übermittelt. Dies eignet sich für Dienste, die aktiv einen Job ausführen, der sofort fortgesetzt werden soll, z. B. das Herunterladen einer Datei.

Weitere Informationen zu diesen Rückgabewerten finden Sie in der verlinkten Referenzdokumentation zu den einzelnen Konstanten.

Dienst starten

Sie können einen Dienst aus einer Aktivität oder einer anderen Anwendungskomponente starten. Dazu übergeben Sie einen Intent an startService() oder startForegroundService(). Das Android-System ruft die Methode onStartCommand() des Dienstes auf und übergibt ihr das Intent, das angibt, welcher Dienst gestartet werden soll.

Hinweis: Wenn deine App auf API-Level 26 oder höher ausgerichtet ist, schränkt das System die Verwendung oder Erstellung von Hintergrunddiensten ein, es sei denn, die App selbst wird im Vordergrund ausgeführt. Wenn eine App einen Dienst im Vordergrund erstellen muss, sollte sie startForegroundService() aufrufen. Mit dieser Methode wird ein Hintergrunddienst erstellt, aber die Methode signalisiert dem System, dass der Dienst sich selbst in den Vordergrund hochgestuft wird. Nachdem der Dienst erstellt wurde, muss er seine startForeground()-Methode innerhalb von fünf Sekunden aufrufen.

Beispielsweise kann eine Aktivität den Beispieldienst im vorherigen Abschnitt (HelloService) mithilfe eines expliziten Intents mit startService() starten, wie hier gezeigt:

Kotlin

startService(Intent(this, HelloService::class.java))

Java

startService(new Intent(this, HelloService.class));

Die Methode startService() wird sofort zurückgegeben und das Android-System ruft die Methode onStartCommand() des Dienstes auf. Wenn der Dienst noch nicht ausgeführt wird, ruft das System zuerst onCreate() und dann onStartCommand() auf.

Wenn der Dienst keine Bindung bietet, ist der mit startService() bereitgestellte Intent der einzige Kommunikationsmodus zwischen der Anwendungskomponente und dem Dienst. Wenn der Dienst jedoch ein Ergebnis zurücksenden soll, kann der Client, der den Dienst startet, eine PendingIntent für einen Broadcast erstellen (mit getBroadcast()) und diese an den Dienst im Intent senden, das den Dienst startet. Der Dienst kann dann mithilfe der Sendung ein Ergebnis liefern.

Mehrere Anfragen zum Starten des Dienstes führen zu mehreren entsprechenden Aufrufen des onStartCommand() des Dienstes. Allerdings ist nur eine Anfrage zum Beenden des Dienstes (mit stopSelf() oder stopService()) erforderlich.

Dienst beenden

Ein gestarteter Dienst muss seinen eigenen Lebenszyklus verwalten. Das heißt, das System stoppt oder löscht den Dienst nur, wenn der Systemspeicher wiederhergestellt werden muss und der Dienst weiter ausgeführt wird, nachdem onStartCommand() zurückgegeben wurde. Der Dienst muss sich selbst durch Aufrufen von stopSelf() beenden oder eine andere Komponente kann ihn durch Aufrufen von stopService() beenden.

Sobald das Beenden mit stopSelf() oder stopService() angefordert wurde, löscht das System den Dienst so schnell wie möglich.

Wenn Ihr Dienst mehrere Anfragen an onStartCommand() gleichzeitig verarbeitet, sollten Sie ihn nicht beenden, wenn Sie die Verarbeitung einer Startanfrage abgeschlossen haben, da Sie möglicherweise eine neue Startanfrage erhalten haben (wenn Sie am Ende der ersten Anfrage beendet werden, wird die zweite beendet). Zur Vermeidung dieses Problems können Sie mit stopSelf(int) dafür sorgen, dass Ihre Anfrage zum Beenden des Dienstes immer auf der letzten Startanfrage basiert. Wenn Sie stopSelf(int) aufrufen, übergeben Sie also die ID der Startanfrage (die an onStartCommand() gesendete startId), der die Stoppanfrage entspricht. Wenn der Dienst dann eine neue Startanfrage erhält, bevor Sie stopSelf(int) aufrufen können, stimmt die ID nicht überein und der Dienst wird nicht beendet.

Achtung:Damit keine Systemressourcen verschwendet und kein Akkustrom verbraucht wird, sollten Sie darauf achten, dass Ihre Anwendung ihre Dienste beendet, wenn sie einsatzbereit ist. Bei Bedarf können andere Komponenten den Dienst durch Aufrufen von stopService() beenden. Auch wenn Sie die Bindung für den Dienst aktivieren, müssen Sie den Dienst immer selbst beenden, falls er einen Aufruf von onStartCommand() erhält.

Weitere Informationen zum Lebenszyklus eines Dienstes finden Sie unten im Abschnitt Lebenszyklus eines Dienstes verwalten.

Gebundenen Dienst erstellen

Mit einem gebundenen Dienst können sich Anwendungskomponenten an ihn binden. Dazu wird bindService() aufgerufen, um eine dauerhafte Verbindung herzustellen. Im Allgemeinen können Komponenten nicht durch Aufrufen von startService() starten.

Erstellen Sie einen gebundenen Dienst, wenn Sie über Aktivitäten und andere Komponenten in Ihrer Anwendung mit dem Dienst interagieren oder einen Teil der Funktionalität der Anwendung über Interprocess Communication (IPC) anderen Anwendungen zur Verfügung stellen möchten.

Implementieren Sie zum Erstellen eines gebundenen Dienstes die Callback-Methode onBind(), damit ein IBinder zurückgegeben wird, das die Schnittstelle für die Kommunikation mit dem Dienst definiert. Andere Anwendungskomponenten können dann bindService() aufrufen, um die Schnittstelle abzurufen und Methoden für den Dienst aufzurufen. Der Dienst dient nur zur Bereitstellung der an ihn gebundenen Anwendungskomponente. Wenn also keine Komponenten an den Dienst gebunden sind, wird er vom System zerstört. Sie müssen einen gebundenen Dienst nicht auf die gleiche Weise beenden wie beim Starten des Dienstes über onStartCommand().

Zum Erstellen eines gebundenen Dienstes müssen Sie die Schnittstelle definieren, die angibt, wie ein Client mit dem Dienst kommunizieren kann. Diese Schnittstelle zwischen dem Dienst und einem Client muss eine Implementierung von IBinder sein und ist das, was der Dienst von der Callback-Methode onBind() zurückgeben muss. Nachdem der Client den IBinder erhalten hat, kann er über diese Schnittstelle mit dem Dienst interagieren.

Es können mehrere Clients gleichzeitig an den Dienst gebunden werden. Wenn ein Client die Interaktion mit dem Dienst abgeschlossen hat, wird unbindService() aufgerufen, um die Bindung aufzuheben. Wenn keine Clients an den Dienst gebunden sind, löscht das System den Dienst.

Es gibt mehrere Möglichkeiten, einen gebundenen Dienst zu implementieren, und die Implementierung ist komplizierter als ein gestarteter Dienst. Aus diesen Gründen wird die Diskussion über gebundene Dienste in einem separaten Dokument über gebundene Dienste aufgeführt.

Benachrichtigungen an den Nutzer senden

Wenn ein Dienst ausgeführt wird, kann er den Nutzer mit Snackbar-Benachrichtigungen oder Statusleistenbenachrichtigungen über Ereignisse informieren.

Eine Snackbar-Benachrichtigung ist eine Nachricht, die nur für einen Moment auf der Oberfläche des aktuellen Fensters angezeigt wird und dann wieder verschwindet. Eine Benachrichtigung in der Statusleiste enthält ein Symbol mit einer Nachricht, das der Nutzer auswählen kann, um eine Aktion auszuführen (z. B. eine Aktivität zu starten).

Normalerweise ist eine Benachrichtigung in der Statusleiste die beste Technik, wenn Hintergrundarbeiten wie ein Dateidownload abgeschlossen sind und der Nutzer jetzt darauf reagieren kann. Wenn der Nutzer die Benachrichtigung aus der erweiterten Ansicht auswählt, kann die Benachrichtigung eine Aktivität starten, z. B. die heruntergeladene Datei anzeigen.

Lebenszyklus eines Dienstes verwalten

Der Lebenszyklus eines Dienstes ist viel einfacher als der einer Aktivität. Sie sollten jedoch besonders genau darauf achten, wie Ihr Dienst erstellt und gelöscht wird, da ein Dienst im Hintergrund ausgeführt werden kann, ohne dass der Nutzer es bemerkt.

Der Dienstlebenszyklus – von der Erstellung bis zu dessen Löschung – kann einem der folgenden beiden Pfade folgen:

  • Ein gestarteter Dienst

    Der Dienst wird erstellt, wenn eine andere Komponente startService() aufruft. Der Dienst wird dann auf unbestimmte Zeit ausgeführt und muss sich durch Aufrufen von stopSelf() selbst stoppen. Eine andere Komponente kann den Dienst auch durch Aufrufen von stopService() beenden. Wenn der Dienst beendet wird, wird er vom System gelöscht.

  • Ein gebundener Dienst

    Der Dienst wird erstellt, wenn eine andere Komponente (ein Client) bindService() aufruft. Der Client kommuniziert dann über eine IBinder-Schnittstelle mit dem Dienst. Der Client kann die Verbindung durch Aufrufen von unbindService() beenden. Mehrere Clients können sich an denselben Dienst binden. Wenn die Bindung bei allen aufgehoben wird, löscht das System den Dienst. Der Dienst muss sich nicht selbst beenden.

Diese beiden Pfade sind nicht vollständig voneinander getrennt. Sie können eine Bindung an einen Dienst herstellen, der bereits mit startService() gestartet wurde. Sie können beispielsweise einen Hintergrundmusikdienst starten, indem Sie startService() mit einem Intent aufrufen, das die zu spielende Musik identifiziert. Später, wenn der Nutzer eine gewisse Kontrolle über den Player ausüben oder Informationen zum aktuellen Titel abrufen möchte, kann sich eine Aktivität durch Aufrufen von bindService() an den Dienst binden. In solchen Fällen wird der Dienst durch stopService() oder stopSelf() erst beendet, wenn alle Clients die Bindung aufgehoben haben.

Lebenszyklus-Callbacks implementieren

Wie eine Aktivität verfügt auch ein Dienst über Lebenszyklus-Callback-Methoden, die Sie implementieren können, um Änderungen am Dienststatus zu überwachen und Aufgaben zu den entsprechenden Zeiten auszuführen. Der folgende grundlegende Dienst zeigt jede der Lebenszyklusmethoden:

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
    }
}

Hinweis:Im Gegensatz zu den Callback-Methoden für den Aktivitätslebenszyklus ist es nicht erforderlich, die Basisklassenimplementierung dieser Callback-Methoden aufzurufen.

Abbildung 2: Der Dienstlebenszyklus. Das Diagramm auf der linken Seite zeigt den Lebenszyklus, wenn der Dienst mit startService() erstellt wird, und das Diagramm auf der rechten Seite zeigt den Lebenszyklus, wenn der Dienst mit bindService() erstellt wird.

Abbildung 2 zeigt die typischen Callback-Methoden für einen Dienst. Obwohl die Abbildung die von startService() erstellten Dienste von den von bindService() erstellten Diensten trennt, beachten Sie, dass jeder Dienst, unabhängig davon, wie er gestartet wird, Clients möglicherweise ermöglichen können, sich an ihn zu binden. Ein Dienst, der ursprünglich mit onStartCommand() gestartet wurde (von einem Client, der startService() aufruft), kann weiterhin einen Aufruf von onBind() empfangen (wenn ein Client bindService() aufruft).

Mit diesen Methoden können Sie diese beiden verschachtelten Schleifen des Lebenszyklus des Dienstes überwachen:

  • Die gesamte Lebensdauer eines Dienstes liegt zwischen dem Aufruf von onCreate() und dem Zeitpunkt, zu dem onDestroy() zurückgegeben wird. Wie bei einer Aktivität führt auch ein Dienst die Ersteinrichtung in onCreate() durch und gibt alle verbleibenden Ressourcen in onDestroy() frei. Ein Musikwiedergabedienst kann beispielsweise den Thread erstellen, in dem die Musik in onCreate() abgespielt wird, und ihn dann in onDestroy() beenden.

    Hinweis: Die Methoden onCreate() und onDestroy() werden für alle Dienste aufgerufen, unabhängig davon, ob sie von startService() oder bindService() erstellt wurden.

  • Die aktive Lebensdauer eines Dienstes beginnt mit einem Aufruf von onStartCommand() oder onBind(). Jeder Methode wird das Intent übergeben, das an startService() oder bindService() übergeben wurde.

    Wenn der Dienst gestartet wird, endet die aktive Lebensdauer mit dem Ende der gesamten Lebensdauer. Der Dienst ist also auch dann aktiv, wenn onStartCommand() zurückgegeben wird. Wenn der Dienst gebunden ist, endet die aktive Lebensdauer, wenn onUnbind() zurückgegeben wird.

Hinweis:Obwohl ein gestarteter Dienst durch einen Aufruf von stopSelf() oder stopService() angehalten wird, gibt es keinen entsprechenden Callback für den Dienst. Es gibt keinen onStop()-Callback. Wenn der Dienst nicht an einen Client gebunden ist, wird er vom System gelöscht, wenn der Dienst beendet wird. onDestroy() ist der einzige empfangene Callback.

Weitere Informationen zum Erstellen eines Dienstes mit Bindung finden Sie im Dokument Bound Services. Es enthält weitere Informationen zur Callback-Methode onRebind() im Abschnitt Lebenszyklus eines gebundenen Dienstes verwalten.