Diensteübersicht

Ein Service ist eine Anwendungskomponente, die im Hintergrund langwierige Operationen durchführen kann. Er bietet keine Benutzeroberfläche. Zu Beginn kann ein Dienst für einige Zeit weiterlaufen, auch wenn der Benutzer zu einer anderen Anwendung wechselt. Außerdem kann sich eine Komponente an einen Dienst binden, um mit ihm zu interagieren und sogar Interprozesskommunikation (IPC) durchzuführen. So kann ein Dienst beispielsweise Netzwerktransaktionen abwickeln, Musik abspielen, Datei-E/A durchführen oder mit einem Inhaltsanbieter interagieren, und das alles im Hintergrund.

Achtung: Ein Dienst wird im Haupt-Thread seines Hosting-Prozesses 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 Operationen auf einem separaten Thread innerhalb des Dienstes ausführen, um ApplicationNot-Responding (ANR)-Fehler zu vermeiden.

Typen von Diensten

Dies sind die drei verschiedenen Arten von Diensten:

Vordergrund

Ein Vordergrunddienst führt eine Operation aus, die für den Benutzer sichtbar ist. Zum Beispiel würde eine Audio-App einen Vordergrunddienst verwenden, um einen Audiotitel abzuspielen. Vordergrunddienste müssen eine Benachrichtigung anzeigen. Vordergrunddienste laufen auch dann weiter, wenn der Benutzer nicht mit der Anwendung interagiert.

Wenn Sie einen Vordergrunddienst verwenden, müssen Sie eine Benachrichtigung anzeigen, damit die Benutzer aktiv wissen, dass der Dienst läuft. Diese Benachrichtigung kann nicht entfernt werden, es sei denn, der Dienst wird entweder gestoppt oder aus dem Vordergrund entfernt.

Erfahren Sie mehr darüber, wie Sie Vordergrunddienste in Ihrer Anwendung konfigurieren können.

Hinweis: Die WorkManager-API bietet eine flexible Möglichkeit zur Planung von Aufgaben und ist in der Lage, diese Aufgaben bei Bedarf als Vordergrunddienste auszuführen. In vielen Fällen ist die Verwendung von WorkManager der direkten Verwendung von Vordergrunddiensten vorzuziehen.

Hintergrund Ein Hintergrunddienst führt einen Vorgang aus, der vom Benutzer nicht direkt wahrgenommen wird. Wenn zum Beispiel eine Anwendung einen Dienst verwendet, um ihren Speicher zu komprimieren, wäre das normalerweise ein Hintergrunddienst.

Hinweis: Wenn Ihre Anwendung auf API-Ebene 26 oder höher abzielt, schränkt das System die Ausführung von Hintergrunddiensten ein, wenn sich die Anwendung selbst nicht im Vordergrund befindet. In den meisten Situationen sollten Sie zum Beispiel nicht im Hintergrund auf Standortinformationen zugreifen. Planen Sie stattdessen Aufgaben mit WorkManager.

Gebunden Ein Dienst ist gebunden, wenn sich eine Anwendungskomponente durch den Aufruf vonbindService()an ihn bindet. Ein gebundener Dienst bietet eine Client-Server-Schnittstelle, die es Komponenten ermöglicht, mit dem Dienst zu interagieren, Anforderungen zu senden und Ergebnisse zu empfangen, und dies sogar prozessübergreifend mit Interprozesskommunikation (IPC). Ein gebundener Dienst läuft nur so lange, wie eine andere Anwendungskomponente an ihn gebunden ist. Mehrere Komponenten können sich gleichzeitig an den Dienst binden, aber wenn alle diese Bindung aufheben, wird der Dienst zerstört.

Obwohl in dieser Dokumentation gestartete und gebundene Dienste im Allgemeinen getrennt behandelt werden, kann Ihr Dienst auf beide Arten funktionieren – er kann gestartet werden (um unbegrenzt zu laufen) und auch eine Bindung zulassen. Es ist einfach eine Frage, ob Sie ein paar Callback-Methoden implementieren: onStartCommand(), damit Komponenten ihn starten können, und onBind(), um eine Bindung zuzulassen.

Unabhängig davon, ob Ihr Dienst gestartet, gebunden oder beides ist, kann jede Anwendungskomponente den Dienst (auch von einer separaten Anwendung aus) auf dieselbe Weise nutzen, wie jede Komponente eine Aktivität nutzen kann, indem sie mit einer Intent gestartet wird. Sie können jedoch den Dienst in der Manifestdatei als privat deklarieren und den Zugriff von anderen Anwendungen blockieren.

Wählen zwischen einem Dienst und einem Thread

Ein Dienst ist einfach eine Komponente, die im Hintergrund laufen kann, auch wenn der Benutzer nicht mit Ihrer Anwendung interagiert.

Wenn Sie Arbeiten außerhalb Ihres Hauptthreads durchführen müssen, aber nur, während der Benutzer mit Ihrer Anwendung interagiert, sollten Sie stattdessen einen neuen Thread im Kontext einer anderen Anwendungskomponente erstellen. Wenn Sie zum Beispiel Musik abspielen wollen, aber nur während Ihre Aktivität läuft, könnten Sie einen Thread in onCreate() erstellen, ihn in onStart() starten und in onStop() stoppen. Ziehen Sie auch die Verwendung von Thread-Pools und Executors aus dem java.util.concurrent-Paket oder Kotlin-Coroutinen anstelle der traditionellenThread-Klasse in Betracht. Weitere Informationen über die Verlagerung der Ausführung in Hintergrund-Threads finden Sie im DokumentThreading on Android.

Erinnern Sie sich daran, dass ein Dienst standardmäßig immer noch im Haupt-Thread Ihrer Anwendung ausgeführt wird. Sie sollten also immer noch einen neuen Thread innerhalb des Dienstes erstellen, wenn er intensive oder blockierende Operationen durchführt.

Die Grundlagen

Um einen Dienst zu erstellen, müssen Sie eine Unterklasse von Service erstellen oder eine der vorhandenen Unterklassen verwenden. In Ihrer Implementierung müssen Sie einige Callback-Methoden überschreiben, die wichtige Aspekte des Lebenszyklus des Dienstes behandeln und einen Mechanismus bereitstellen, der es den Komponenten ermöglicht, sich an den Dienst zu binden, falls erforderlich. Dies sind die wichtigsten Callback-Methoden, die Sie überschreiben sollten:

onStartCommand()Das System ruft diese Methode auf, indem esstartService()aufruft, wenn eine andere Komponente (z. B. eine Aktivität) anfordert, dass der Dienst gestartet wird.Wenn diese Methode ausgeführt wird, wird der Dienst gestartet und kann unbegrenzt im Hintergrund laufen. Wenn Sie dies implementieren, liegt es in Ihrer Verantwortung, den Dienst zu stoppen, wenn seine Arbeit beendet ist, indem SiestopSelf()oderstopService()aufrufen. Wenn Sie nur die Bindung bereitstellen wollen, brauchen Sie diese Methode nicht zu implementieren.onBind()Das System ruft diese Methode auf, indem esbindService()aufruft, wenn eine andere Komponente sich mit dem Dienst verbinden will (z. B. um RPC auszuführen).In Ihrer Implementierung dieser Methode müssen Sie eine Schnittstelle bereitstellen, über die Clients mit dem Dienst kommunizieren, indem Sie einIBinderzurückgeben. Sie müssen diese Methode immer implementieren; wenn Sie jedoch keine Bindung zulassen wollen, sollten Sie null zurückgeben.onCreate()Das System ruft diese Methode auf, um einmalige Einrichtungsprozeduren durchzuführen, wenn der Dienst zum ersten Mal erstellt wird (bevor er entwederonStartCommand()oderonBind()aufruft). Wenn der Dienst bereits läuft, wird diese Methode nicht aufgerufen.onDestroy()Das System ruft diese Methode auf, wenn der Dienst nicht mehr verwendet und zerstört wird. Ihr Dienst sollte dies implementieren, um alle Ressourcen wie Threads, registrierte Hörer oder Empfänger zu bereinigen. Dies ist der letzte Aufruf, den der Dienst erhält.

Wenn eine Komponente den Dienst durch den Aufruf von startService() startet (was zu einem Aufruf von onStartCommand() führt), läuft der Dienst weiter, bis er sich selbst mit stopSelf() stoppt oder eine andere Komponente ihn durch den Aufruf von stopService() stoppt.

Wenn eine Komponente bindService() aufruft, um den Dienst zu erstellen und onStartCommand() nicht aufgerufen wird, läuft der Dienst nur so lange, wie die Komponente an ihn gebunden ist.

Das Android-System stoppt einen Dienst nur dann, wenn der Speicherplatz knapp wird und es die Systemressourcen für die Aktivität, die den Benutzerfokus hat, wiederherstellen muss. Wenn der Dienst an eine Aktivität gebunden ist, die den Benutzerfokus hat, ist es weniger wahrscheinlich, dass er beendet wird; wenn der Dienst als im Vordergrund laufend deklariert ist, wird er selten beendet.Wenn der Dienst gestartet wird und lange läuft, senkt das System mit der Zeit seine Position in der Liste der Hintergrundaufgaben, und der Dienst wird sehr anfällig für das Beenden – wenn Ihr Dienst gestartet wird, müssen Sie ihn so gestalten, dass er mit Neustarts durch das System gut umgehen kann. Wenn das System Ihren Dienst beendet, startet es ihn neu, sobald Ressourcen verfügbar sind, aber dies hängt auch von dem Wert ab, den Sie von onStartCommand() zurückgeben. Weitere Informationen darüber, wann das System einen Dienst zerstört, finden Sie im Dokument Prozesse und Threading.

In den folgenden Abschnitten erfahren Sie, wie Sie die MethodenstartService() undbindService() für Dienste erstellen können und wie Sie sie von anderen Anwendungskomponenten aus verwenden können.

Deklarieren eines Dienstes im Manifest

Sie müssen alle Dienste in der Manifestdatei Ihrer Anwendung deklarieren, genauso wie Sie es für Aktivitäten und andere Komponenten tun.

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

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

Weitere Informationen zum Deklarieren Ihres Dienstes im Manifest finden Sie in der <service>-Elementreferenz.

Es gibt weitere Attribute, die Sie in das <service>-Element aufnehmen können, um Eigenschaften wie die zum Starten des Dienstes erforderlichen Berechtigungen und den Prozess, in dem der Dienst ausgeführt werden soll, zu definieren. Das android:name-Attribut ist das einzige erforderliche Attribut, das den Klassennamen des Dienstes angibt. Nachdem Sie Ihre Anwendung veröffentlicht haben, lassen Sie diesen Namen unverändert, um das Risiko eines Codebruchs aufgrund der Abhängigkeit von expliziten Intents zum Starten oder Binden des Dienstes zu vermeiden (lesen Sie den Blogbeitrag ThingsThat Cannot Change).

Achtung: Um sicherzustellen, dass Ihre Anwendung sicher ist, verwenden Sie immer einen expliziten Intent, wenn Sie einen Service starten und deklarieren Sie keine Intent-Filter für Ihre Dienste. Die Verwendung einer impliziten Absicht zum Starten eines Dienstes stellt ein Sicherheitsrisiko dar, da Sie nicht sicher sein können, welcher Dienst auf die Absicht antwortet, und der Benutzer nicht sehen kann, welcher Dienst gestartet wird. Ab Android 5.0 (API-Level 21) löst das System eine Ausnahme aus, wenn Sie bindService() mit einer impliziten Absicht aufrufen.

Sie können sicherstellen, dass Ihr Dienst nur Ihrer App zur Verfügung steht, indem Sie das android:exportedAttribut einschließen und es auf false setzen. Dadurch wird verhindert, dass andere Anwendungen Ihren Dienst starten, selbst wenn Sie eine explizite Absicht verwenden.

Hinweis: Benutzer 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 stoppen. Um zu vermeiden, dass Ihr Dienst versehentlich von Benutzern gestoppt wird, müssen Sie das Attribut android:description zum Element <service> in Ihrem App-Manifest hinzufügen. Geben Sie in der Beschreibung einen kurzen Satz an, der erklärt, was der Dienst tut und welche Vorteile er bietet.

Erstellen eines gestarteten Dienstes

Ein gestarteter Dienst ist ein Dienst, der von einer anderen Komponente durch den Aufruf von startService() gestartet wird, was zu einem Aufruf der onStartCommand()-Methode des Dienstes führt.

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 laufen, auch wenn die Komponente, die ihn gestartet hat, zerstört wird. Daher sollte der Dienst sich selbst stoppen, wenn seine Aufgabe abgeschlossen ist, indem er stopSelf() aufruft, oder eine andere Komponente kann ihn durch den Aufruf von stopService() stoppen.

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

Angenommen, eine Aktivität muss einige Daten in einer Online-Datenbank speichern. Die Aktivität kann einen begleitenden Dienst starten und ihm die zu speichernden Daten übermitteln, indem sie eine Absicht an startService() übergibt. Der Dienst empfängt die Absicht in onStartCommand(), verbindet sich mit dem Internet und führt die Datenbanktransaktion durch. Wenn die Transaktion abgeschlossen ist, beendet sich der Dienst selbst und wird zerstört.

Achtung: Ein Dienst läuft standardmäßig im selben Prozess wie die Anwendung, in der er deklariert ist, und im Hauptthread dieser Anwendung. Wenn Ihr Dienst intensive oder blockierende Operationen durchführt, während der Benutzer mit einer Aktivität derselben Anwendung interagiert, verlangsamt der Dienst die Leistung der Aktivität. Um Auswirkungen auf die Anwendungsleistung zu vermeiden, starten Sie einen neuen Thread innerhalb des Dienstes.

Die Klasse Service 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 Haupt-Thread Ihrer Anwendung, was die Leistung jeder Aktivität, die Ihre Anwendung ausführt, verlangsamen kann.

Das Android-Framework bietet auch die IntentServiceUnterklasse von Service, die einen Worker-Thread verwendet, um alle Startanfragen zu verarbeiten, eine nach der anderen. Die Verwendung dieser Klasse wird für neue Apps nicht empfohlen, da sie ab Android 8 Oreo aufgrund der Einführung von Ausführungsbeschränkungen im Hintergrund nicht gut funktioniert und ab Android 11 veraltet ist. 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, jedoch sollten Sie für die meisten Anwendungsfälle stattdessen WorkManager verwenden. Konsultieren Sie den Leitfaden zur Hintergrundverarbeitung unter Android, um zu sehen, ob es eine Lösung gibt, die Ihren Bedürfnissen entspricht.

Erweitern der Service-Klasse

Sie können die Service-Klasse erweitern, um jede eingehende Absicht zu behandeln. So könnte eine grundlegende Implementierung 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 behandelt alle eingehenden Aufrufe in onStartCommand()und sendet die Arbeit an einen Handler, der in einem Hintergrund-Thread läuft. Sie können den Code ändern, um die Arbeit in einem Thread-Pool auszuführen, wenn Sie beispielsweise mehrere Anfragen gleichzeitig ausführen möchten.

Beachten Sie, dass die Methode onStartCommand() eine ganze Zahl zurückgeben muss. Die Ganzzahl ist ein Wert, der beschreibt, wie das System den Dienst fortsetzen soll, falls er vom System beendet wird. Der Rückgabewert von onStartCommand() muss eine der folgenden Konstanten sein:

START_NOT_STICKYWenn das System den Dienst nach der Rückgabe vononStartCommand()beendet, erstellen Sie den Dienst nicht neu, es sei denn, es stehen noch Einträge an, die geliefert werden müssen. Dies ist die sicherste Option, um zu vermeiden, dass der Dienst ausgeführt wird, wenn dies nicht erforderlich ist und wenn Ihre Anwendung alle nicht abgeschlossenen Aufträge einfach neu starten kann.START_STICKYWenn das System den Dienst nach der Rückkehr vononStartCommand()beendet, erstellen Sie den Dienst neu und rufen SieonStartCommand()auf, aber liefern Sie den letzten Intent nicht erneut, sondern rufen SieonStartCommand()mit einem Null-Intent auf, es sei denn, es stehen Intents zum Starten des Dienstes an. In diesem Fall werden diese Absichten zugestellt. Dies eignet sich für Medienplayer (oder ähnliche Dienste), die keine Befehle ausführen, sondern auf unbestimmte Zeit laufen und auf einen Auftrag warten.START_REDELIVER_INTENTWenn das System den Dienst beendet, nachdemonStartCommand()zurückgekehrt ist, erstellen Sie den Dienst neu und rufenonStartCommand()mit der letzten Absicht auf, die an den Dienst geliefert wurde. Alle ausstehenden Intents werden der Reihe nach geliefert. Dies eignet sich für Dienste, die aktiv eine Aufgabe ausführen, die sofort wieder aufgenommen werden soll, z. B. das Herunterladen einer Datei.

Weitere Details zu diesen Rückgabewerten finden Sie in der verlinkten referenzierten Dokumentation für jede Konstante.

Starten eines Dienstes

Sie können einen Dienst von einer Activity oder einer anderen Anwendungskomponente aus starten, indem Sie ein Intent an startService() oder startForegroundService() übergeben. Das Android-System ruft die onStartCommand()-Methode des Dienstes auf und übergibt ihm die Intent, die angibt, welcher Dienst gestartet werden soll.

Hinweis: Wenn Ihre Anwendung auf API-Level 26 oder höher abzielt, schränkt das System die Verwendung oder Erstellung von Hintergrunddiensten ein, es sei denn, die Anwendung selbst befindet sich im Vordergrund. Wenn eine Anwendung einen Vordergrunddienst erstellen muss, sollte die Anwendung startForegroundService() aufrufen. Diese Methode erstellt einen Hintergrunddienst, aber die Methode signalisiert dem System, dass der Dienst in den Vordergrund treten wird. Sobald der Dienst erstellt wurde, muss er seine startForeground() Methode innerhalb von fünf Sekunden aufrufen.

Eine Aktivität kann beispielsweise den Beispieldienst aus dem vorigen Abschnitt (HelloService) mit einem expliziten Intent mit startService() starten, wie hier gezeigt:

Kotlin

Intent(this, HelloService::class.java).also { intent -> startService(intent)}

Java

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

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

Wenn der Dienst nicht auch eine Bindung bereitstellt, ist der mit startService() gelieferte 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, ein PendingIntent für einen Broadcast (mit getBroadcast()) erstellen und es dem Dienst im Intent, der den Dienst startet, übergeben. Der Dienst kann dann den Broadcast verwenden, um ein Ergebnis zu liefern.

Mehrere Anfragen zum Starten des Dienstes führen zu mehreren entsprechenden Aufrufen desonStartCommand() des Dienstes. Um den Dienst zu stoppen, ist jedoch nur eine Anfrage zum Stoppen des Dienstes (mit stopSelf() oder stopService()) erforderlich.

Stoppen eines Dienstes

Ein gestarteter Dienst muss seinen eigenen Lebenszyklus verwalten. Das heißt, das System hält nicht an, um den Dienst zu zerstören, es sei denn, es muss den Systemspeicher wiederherstellen und der Dienst läuft weiter, nachdem onStartCommand() zurückgekehrt ist. Der Dienst muss sich selbst stoppen, indem er stopSelf() aufruft, oder eine andere Komponente kann ihn stoppen, indem sie stopService() aufruft.

Wenn er mit stopSelf() oder stopService() zum Stoppen aufgefordert wird, zerstört das System den Dienst so bald wie möglich.

Wenn Ihr Dienst mehrere Anfragen an onStartCommand() gleichzeitig bearbeitet, sollten Sie den Dienst nicht anhalten, wenn Sie mit der Bearbeitung einer Startanfrage fertig sind, da Sie möglicherweise eine neue Startanfrage erhalten haben (das Anhalten am Ende der ersten Anfrage würde die zweite beenden). Um dieses Problem zu vermeiden, können Sie stopSelf(int) verwenden, um sicherzustellen, dass Ihre Anforderung zum Anhalten des Dienstes immer auf der letzten Startanforderung basiert. Das heißt, wenn Sie stopSelf(int) aufrufen, übergeben Sie die ID der Startanforderung (die an onStartCommand() gelieferte startId), auf die Ihre Stoppanforderung antwortet. Wenn der Dienst dann eine neue Startanforderung erhält, bevor Sie stopSelf(int) aufrufen können, stimmt die ID nicht überein und der Dienst wird nicht angehalten.

Achtung: Um die Verschwendung von Systemressourcen und den Verbrauch von Batteriestrom zu vermeiden, stellen Sie sicher, dass Ihre Anwendung ihre Dienste anhält, wenn sie mit der Arbeit fertig ist.stopService() Falls erforderlich, können andere Komponenten den Dienst durch den Aufruf von stopService() anhalten. Selbst wenn Sie die Bindung für den Dienst aktivieren, müssen Sie den Dienst immer selbst stoppen, wenn er einen Aufruf von onStartCommand() erhält.

Weitere Informationen über den Lebenszyklus eines Dienstes finden Sie im Abschnitt über die Verwaltung des Lebenszyklus eines Dienstes.

Erstellen eines gebundenen Dienstes

Ein gebundener Dienst ist ein Dienst, der es Anwendungskomponenten ermöglicht, sich durch den Aufruf von bindService() an ihn zu binden, um eine dauerhafte Verbindung herzustellen.In der Regel können Komponenten ihn nicht durch den Aufruf von startService() starten.

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

Um einen gebundenen Dienst zu erstellen, implementieren Sie die Callback-Methode onBind(), um ein IBinder zurückzugeben, das die Schnittstelle für die Kommunikation mit dem Dienst definiert. Andere Anwendungskomponenten können dann bindService() aufrufen, um die Schnittstelle abzurufen und mit dem Aufruf von Methoden des Dienstes zu beginnen. Der Dienst lebt nur, um die Anwendungskomponente zu bedienen, die an ihn gebunden ist. Wenn also keine Komponenten mehr an den Dienst gebunden sind, wird er vom System zerstört. Sie müssen einen gebundenen Dienst nicht auf dieselbe Weise stoppen, wie Sie es müssen, wenn der Dienst über onStartCommand() gestartet wird.

Um einen gebundenen Dienst zu erstellen, 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 Ihr Dienst von der onBind() Callback-Methode zurückgeben muss. Nachdem der Client die IBinder erhalten hat, kann er beginnen, mit dem Dienst über diese Schnittstelle zu interagieren.

Mehrere Clients können sich gleichzeitig an den Dienst binden. Wenn ein Client die Interaktion mit dem Dienst beendet hat, ruft er unbindService() auf, um die Bindung aufzuheben.

Wenn keine Clients mehr an den Dienst gebunden sind, zerstört das System den Dienst.

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

Benachrichtigungen an den Benutzer senden

Wenn ein Dienst läuft, kann er den Benutzer mit Toast-Benachrichtigungen oder Statusleisten-Benachrichtigungen über Ereignisse informieren.

Eine Toast-Benachrichtigung ist eine Nachricht, die nur einen Moment lang auf der Oberfläche des aktuellen Fensters erscheint und dann verschwindet. Eine Statusleisten-Benachrichtigung bietet ein Symbol in der Statusleiste mit einer Nachricht, die der Benutzer auswählen kann, um eine Aktion auszuführen (z. B. eine Aktivität zu starten).

In der Regel ist eine Statusleisten-Benachrichtigung die beste Technik, wenn eine Hintergrundarbeit, z. B. ein Dateidownload, abgeschlossen ist und der Benutzer nun darauf reagieren kann. Wenn der Benutzer die Benachrichtigung in der erweiterten Ansicht auswählt, kann die Benachrichtigung eine Aktivität starten (z. B. die Anzeige der heruntergeladenen Datei).

Weitere Informationen finden Sie in den Entwicklerhandbüchern Toast-Benachrichtigungen oder Statusleisten-Benachrichtigungen.

Verwalten des Lebenszyklus eines Dienstes

Der Lebenszyklus eines Dienstes ist viel einfacher als der einer Aktivität. Es ist jedoch umso wichtiger, dass Sie genau darauf achten, wie Ihr Dienst erstellt und zerstört wird, da ein Dienst im Hintergrund laufen kann, ohne dass der Benutzer dies bemerkt.

Der Lebenszyklus eines Dienstes – von seiner Erstellung bis zu seiner Zerstörung – kann einem der beiden folgenden Pfade folgen:

  • Ein gestarteter Dienst

    Der Dienst wird erstellt, wenn eine andere Komponente startService() aufruft. Der Dienst läuft dann auf unbestimmte Zeit und muss sich selbst durch den Aufruf von stopSelf() anhalten. Eine andere Komponente kann den Dienst auch durch den Aufruf von stopService() stoppen. Wenn der Dienst gestoppt wird, wird er vom System zerstört.

  • Ein gebundener Dienst

    Der Dienst wird erstellt, wenn eine andere Komponente (ein Client) bindService() aufruft. Der Client kommuniziert dann mit dem Dienst über eine IBinder Schnittstelle. Der Client kann die Verbindung durch den Aufruf von unbindService() beenden. Mehrere Clients können sich an denselben Dienst binden, und wenn alle diese Bindung aufheben, wird der Dienst vom System zerstört. Der Dienst braucht sich nicht selbst zu beenden.

Diese beiden Wege sind nicht völlig getrennt. Sie können sich mit startService() an einen Dienst binden, der bereits gestartet ist. Sie können zum Beispiel einen Hintergrundmusikdienst starten, indem Sie startService() mit einem Intent aufrufen, der die abzuspielende Musik identifiziert. Später, wenn der Benutzer die Kontrolle über den Player ausüben oder Informationen über den aktuellen Titel erhalten möchte, kann eine Aktivität durch den Aufruf von bindService() an den Dienst gebunden werden. In Fällen wie diesem stoppt stopService() oder stopSelf() den Dienst erst, wenn alle Clients die Bindung aufheben.

Implementieren der Lebenszyklus-Callbacks

Wie eine Aktivität hat auch ein Dienst Lebenszyklus-Callback-Methoden, die Sie implementieren können, um Änderungen im Zustand des Dienstes zu überwachen und die Arbeit zu den entsprechenden Zeitpunkten durchzuführen. Der folgende Skeletonservice demonstriert jede der Lifecycle-Methoden:

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 () { // The service is being created } override fun (intent: Intent?, flags: Int, startId: Int): Int { // The service is starting, due to a call to startService() return startMode } override fun (intent: Intent): IBinder? { // A client is binding to the service with bindService() return binder } override fun (intent: Intent): Boolean { // All clients have unbound with unbindService() return allowRebind } override fun (intent: Intent) { // A client is binding to the service with bindService(), // after onUnbind() has already been called } override fun () { // 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 () { // The service is being created } @Override public int (Intent intent, int flags, int startId) { // The service is starting, due to a call to  return startMode; } @Override public IBinder (Intent intent) { // A client is binding to the service with  return binder; } @Override public boolean (Intent intent) { // All clients have unbound with  return allowRebind; } @Override public void (Intent intent) { // A client is binding to the service with , // after onUnbind() has already been called } @Override public void () { // The service is no longer used and is being destroyed }}

Hinweis: Im Gegensatz zu den Lifecycle-Callback-Methoden einer Activity ist es nicht erforderlich, die Implementierung dieser Callback-Methoden in der Superklasse aufzurufen.

Abbildung 2. Der Lebenszyklus eines Dienstes. 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 Dienste, die mit startService() erstellt wurden, von denen unterscheidet, die mit bindService() erstellt wurden, sollte man bedenken, dass jeder Dienst, egal wie er gestartet wurde, potenziell Clients erlauben kann, sich an ihn zu binden.Ein Dienst, der ursprünglich mit onStartCommand() gestartet wurde (durch einen Client, der startService() aufruft), kann immer noch einen Aufruf an onBind() erhalten (wenn ein Client bindService() aufruft).

Indem Sie diese Methoden implementieren, können Sie diese beiden verschachtelten Schleifen des Lebenszyklus eines Dienstes überwachen:

  • Die gesamte Lebensdauer eines Dienstes liegt zwischen dem Zeitpunkt, an dem onCreate() aufgerufen wird, und dem Zeitpunkt, an dem onDestroy() zurückkehrt. Wie eine Aktivität wird ein Dienst in onCreate() initial eingerichtet und gibt in onDestroy() alle verbleibenden Ressourcen frei. Zum Beispiel kann ein Musikwiedergabedienst den Thread, in dem die Musik abgespielt wird, in onCreate() erstellen und dann in onDestroy() beenden.

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

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

    Wenn der Dienst gestartet wird, endet die aktive Lebensdauer zum gleichen Zeitpunkt, an dem die gesamte Lebensdauer endet (der Dienst ist auch nach der Rückkehr von onStartCommand() noch aktiv). Wenn der Dienst gebunden ist, endet die aktive Lebensdauer, wenn onUnbind() zurückkehrt.

Hinweis: Obwohl ein gestarteter Dienst durch einen Aufruf von stopSelf() oder stopService() gestoppt wird, gibt es keinen entsprechenden Callback für diesen Dienst (es gibt keinen onStop() Callback). Wenn der Dienst nicht an einen Client gebunden ist, zerstört das System ihn, wenn der Dienst gestoppt wird – onDestroy() ist der einzige empfangene Callback.

Weitere Informationen zum Erstellen eines Dienstes, der eine Bindung bietet, finden Sie im Dokument Gebundene Dienste, das weitere Informationen über die onRebind()Callback-Methode im Abschnitt über die Verwaltung des Lebenszyklus eines gebundenen Dienstes enthält.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.