Ein Service
ist ein
Anwendungskomponente, die
lang andauernde Vorgänge im Hintergrund. Es gibt keine Benutzeroberfläche. Einmal
gestartet wurde, wird ein Dienst möglicherweise noch einige Zeit ausgeführt, auch wenn der Nutzer zu einem anderen
. Darüber hinaus kann eine Komponente an einen Dienst gebunden werden, um mit ihm zu interagieren und sogar
Interprocess Communication (IPC) Ein Dienst kann z. B.
Netzwerktransaktionen verarbeiten,
Musik machen, Datei-E/A durchführen oder mit einem Contentanbieter interagieren – alles im Hintergrund.
Achtung:Ein Dienst wird im Hauptthread seines Hostings ausgeführt. Prozess; Der Dienst erstellt keinen eigenen Thread und erstellt keinen in einem separaten Prozess ausgeführt werden, sofern Sie nichts anderes angeben. Sie sollten alle blockierenden Vorgänge Einen separaten Thread innerhalb des Dienstes, um Anwendungen zu vermeiden ANR-Fehler (Not Responding).
Arten von Diensten
Es gibt drei verschiedene Arten von Diensten:
- Vordergrund
-
Ein Dienst im Vordergrund führt einen Vorgang aus, der für den Nutzer Nutzer. Eine Audio-App würde z. B. einen Dienst im Vordergrund verwenden, um Audiotrack. Dienste im Vordergrund müssen eine Benachrichtigung anzeigen. Dienste im Vordergrund werden weiter ausgeführt, auch wenn der Nutzer nicht interagiert mit der App.
Wenn Sie einen Dienst im Vordergrund verwenden, müssen Sie eine Benachrichtigung anzeigen, erkennen Nutzer aktiv, dass der Dienst ausgeführt wird. Diese Benachrichtigung kann nicht geschlossen werden, sofern der Dienst nicht angehalten oder aus dem im Vordergrund.
Weitere Informationen zur Konfiguration Dienste im Vordergrund in Ihrem
Hinweis: Das Die WorkManager API bietet eine flexible Möglichkeit, Aufgaben zu planen. können ausführen, diese Jobs bei Bedarf als Dienste im Vordergrund an. In vielen Fällen wird die Verwendung WorkManager ist der direkten Verwendung von Diensten im Vordergrund zu empfehlen.
- Hintergrund
- Ein Hintergrunddienst führt einen Vorgang aus, der von
Nutzenden. Wenn z. B. eine App einen Dienst
zur Verdichtung des Speichers verwendet hat,
normalerweise ein Hintergrunddienst.
Hinweis:Wenn Ihre App auf API-Level 26 oder höher ausgerichtet ist, legt das System Einschränkungen für die Hintergrundausführung fest. , wenn die App selbst nicht im Vordergrund ausgeführt wird. In den meisten sollten Sie zum Beispiel nicht auf Standortinformationen Hintergrund. Stattdessen Aufgaben planen mit WorkManager.
- Gebunden
- Ein Dienst ist gebunden, wenn eine Anwendungskomponente durch Aufrufen von
bindService()
an ihn gebunden wird. Ein gebundener Dienst bietet einen Client-Server, Schnittstelle, über die Komponenten mit dem Dienst interagieren, Anfragen senden, Ergebnisse empfangen und zwar prozessübergreifend mit Interprocess Communication (IPC). Ein gebundener Dienst wird nur ausgeführt solange eine andere Anwendungskomponente an sie gebunden ist. Mehrere Komponenten können an die aber wenn alle die Bindungen aufheben, wird der Dienst gelöscht.
Obwohl in dieser Dokumentation
gestartete und gebundene Dienste im Allgemeinen separat behandelt werden,
kann Ihr Dienst auf beide Arten funktionieren: Er kann gestartet werden, d. h., er kann auf unbestimmte Zeit ausgeführt werden.
Bindung. Es müssen nur einige Callback-Methoden implementiert werden: onStartCommand()
, damit die Komponenten sie starten können, und onBind()
, um eine Bindung zuzulassen.
Unabhängig davon, ob Ihr Dienst gestartet, gebunden oder beides ist,
können den Dienst (sogar aus einer separaten Anwendung) auf dieselbe Weise nutzen, wie jede Komponente
einer Aktivität, indem Sie sie mit einem Intent
starten. Sie können jedoch
den Dienst in der Manifestdatei als privat kennzeichnen und den Zugriff anderer Anwendungen blockieren.
Weitere Informationen hierzu finden Sie im Abschnitt Dienst deklarieren in der
Manifestdatei.
Zwischen einem Dienst und einem Thread wählen
Ein Dienst ist einfach eine Komponente, die im Hintergrund ausgeführt werden kann, selbst wenn der Nutzer selbst mit Ihrer Anwendung interagieren. Erstellen Sie also nur dann einen Dienst, die Sie brauchen.
Wenn Sie außerhalb Ihres Hauptthreads arbeiten müssen, aber nur während der Nutzer interagiert
mit Ihrer Anwendung verwenden, sollten Sie stattdessen einen neuen Thread im Kontext einer anderen Anwendung erstellen
Komponente. Wenn du z. B. etwas Musik hören möchtest, aber nur während der Aktivität läuft, kannst du
können Sie eine Unterhaltung in onCreate()
erstellen,
beginnen Sie mit der Ausführung in onStart()
,
und beende es in onStop()
.
Verwenden Sie auch Threadpools und Executors aus dem Paket java.util.concurrent
.
oder Kotlin-Koroutinen anstelle der traditionellen
Thread
. Weitere Informationen finden Sie in der
Dokument Threading on Android mit weiteren Informationen zu
die Ausführung in
Hintergrundthreads verschieben.
Wenn Sie einen Dienst verwenden, wird er weiterhin im Hauptthread Ihrer Anwendung ausgeführt, indem er Daher sollten Sie innerhalb des Dienstes trotzdem einen neuen Thread erstellen, wenn er blockierende Vorgänge.
Grundlagen
Zum Erstellen eines Dienstes müssen Sie eine abgeleitete Klasse von Service
erstellen oder eine verwenden
der vorhandenen abgeleiteten Klassen an. In Ihrer Implementierung müssen Sie einige Callback-Methoden überschreiben, die
wichtige Aspekte des Dienstlebenszyklus verarbeiten und einen Mechanismus bereitstellen, der es den Komponenten ermöglicht,
binden Sie sie gegebenenfalls an den Dienst. Dies sind die wichtigsten Callback-Methoden, die ihr
überschreiben:
onStartCommand()
- Das System ruft diese Methode durch Aufrufen von
startService()
auf, 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 im auf unbestimmte Zeit im Hintergrund ab. Wenn Sie dies implementieren, liegt es in Ihrer Verantwortung, den Dienst zu beenden, die Arbeit durch Aufrufen vonstopSelf()
oderstopService()
abgeschlossen ist. Wenn Sie nur eine Bindung bereitstellen möchten, diese Methode implementieren müssen. onBind()
- Das System ruft diese Methode durch Aufrufen von
bindService()
auf, wenn eine andere Komponente eine Bindung an den Dienst herstellen möchte (z. B. um einen RPC auszuführen). Bei der Implementierung dieser Methode müssen Sie eine Schnittstelle bereitstellen, die Clients verwenden, um mit dem Dienst zu kommunizieren, indem einIBinder
zurückgegeben wird. Sie müssen immer diese Methode implementieren; Wenn Sie jedoch keine Bindung zulassen möchten, null. onCreate()
- Das System ruft diese Methode auf, um einmalige Einrichtungsschritte auszuführen, wenn der Dienst
(bevor entweder
onStartCommand()
oderonBind()
. Wenn der Dienst bereits ausgeführt wird, ist diese Methode nicht aufgerufen. onDestroy()
- Das System ruft diese Methode auf, wenn der Dienst nicht mehr verwendet wird und gelöscht wird. Ihr Dienst sollte dies implementieren, um Ressourcen wie Threads, registrierte Hörer oder Empfänger. Dies ist der letzte Aufruf, den der Dienst erhält.
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 sie mit stopSelf()
oder einem anderen
beendet ihn durch Aufrufen von stopService()
.
Wenn eine Komponente den Aufruf
bindService()
, um den Dienst zu erstellen und onStartCommand()
nicht aufgerufen wird, wird der Dienst ausgeführt.
solange die Komponente daran gebunden ist. Nachdem der Dienst von
allen Clients getrennt wurde,
vom System zerstört.
Das Android-System stoppt einen Dienst nur dann, wenn nur noch wenig Arbeitsspeicher verfügbar ist, und muss das System wiederherstellen
Ressourcen für die Aktivität zu finden,
die auf die Nutzenden ausgerichtet ist. Wenn der Dienst an eine Aktivität gebunden ist,
ist die Wahrscheinlichkeit geringer, dass sie getötet werden. Wenn der Dienst für die Ausführung im Vordergrund deklariert wird, wird er selten beendet.
Wenn der Dienst gestartet wird und lange andauert, senkt sich die Systempositionen.
im Laufe der Zeit in der Liste der Hintergrundaufgaben auf, wodurch der Dienst sehr anfällig für
killing: Wenn Ihr Dienst gestartet wird, müssen Sie ihn so konzipieren, dass Neustarts ordnungsgemäß ausgeführt werden.
durch das System. Wenn das System Ihren Dienst beendet, wird er neu gestartet, sobald Ressourcen verfügbar sind.
verfügbar, aber dies hängt auch vom Wert ab, den Sie von onStartCommand()
zurückgeben. Weitere Informationen
Informationen dazu, wann das System einen Dienst zerstören könnte, finden Sie unter Prozesse und Threading.
Dokument.
In den folgenden Abschnitten erfahren Sie, wie Sie
startService()
und
bindService()
-Dienstmethoden und die Verwendung
aus anderen Anwendungskomponenten.
Dienst im Manifest deklarieren
Sie müssen alle Dienste in der Manifest-Datei, genau wie Aktivitäten und andere Komponenten.
Fügen Sie ein <service>
-Element hinzu, um Ihren Dienst zu deklarieren
als Kind von <application>
-Elements. Hier ein Beispiel:
<manifest ... > ... <application ... > <service android:name=".ExampleService" /> ... </application> </manifest>
Siehe Element <service>
finden Sie weitere Informationen zum Deklarieren Ihres Dienstes im Manifest.
Es gibt weitere Attribute, die Sie im Element <service>
angeben können,
Attribute wie die Berechtigungen definieren, die zum Starten des Dienstes und
die der Dienst ausführen soll. Die android:name
ist das einzige erforderliche Attribut. Es gibt den Klassennamen der Dienstleistung an. Nachher
Wenn Sie Ihre Anwendung veröffentlichen, lassen Sie diesen Namen unverändert, um zu verhindern, dass
Code aufgrund der Abhängigkeit von expliziten Intents, um den Dienst zu starten oder zu binden (siehe Blogpost, Things
Das kann nicht geändert werden).
Achtung: Für die Sicherheit Ihrer App sollten Sie immer einen
expliziten Intent beim Starten eines Service
und Deklarieren Sie keine Intent-Filter für
Ihre Dienste zu optimieren. Das Starten eines Dienstes mit einem impliziten Intent stellt ein Sicherheitsrisiko dar, da Sie
sicher sein, welcher Dienst auf den Intent reagiert, und der Nutzer kann nicht sehen, welcher Dienst
beginnt. Ab Android 5.0 (API-Level 21) löst das System eine Ausnahme aus, wenn du die
bindService()
mit einem impliziten Intent.
Sie können dafür sorgen, dass Ihr Dienst nur für Ihre App verfügbar ist, indem Sie
einschließlich android:exported
Attribut und legen es auf false
fest. Dadurch wird verhindert, dass andere Apps Ihren
auch bei Verwendung eines expliziten Intents.
Hinweis:
Nutzer können sehen, welche Dienste auf ihrem Gerät ausgeführt werden. Wenn sie sehen,
die sie nicht kennen oder denen sie nicht vertrauen, können sie den Dienst beenden. In
um zu vermeiden, dass Ihr Dienst von Nutzern versehentlich beendet wird, müssen Sie
zum Hinzufügen von
android:description
dem Attribut
<service>
-Element in Ihrem App-Manifest. In der Beschreibung
Beschreiben Sie in einem kurzen Satz, wozu die Dienstleistung dient und welche Vorteile sie bietet.
die es bietet.
Gestarteten Dienst erstellen
Bei einem gestarteten Dienst startet eine andere Komponente durch Aufrufen von startService()
, was zu einem Aufruf des
onStartCommand()
-Methode.
Wenn ein Dienst gestartet wird,
hat er einen Lebenszyklus, der unabhängig
die den Vorgang gestartet hat. Der Dienst kann auf unbestimmte Zeit im Hintergrund ausgeführt werden, auch wenn
wird die Komponente, die sie gestartet hat, zerstört. Daher sollte der Dienst sich selbst beenden, wenn sein Job
durch Aufrufen von stopSelf()
abgeschlossen ist oder eine andere Komponente
stoppen Sie ihn durch Aufrufen von stopService()
.
Der Dienst kann über eine Anwendungskomponente, z. B. eine Aktivität, durch Aufrufen von startService()
und Übergeben eines Intent
-Objekts gestartet werden.
, der den Dienst angibt und alle Daten enthält, die der Dienst nutzen kann. Der Dienst erhält
Intent
in der onStartCommand()
-Methode.
Angenommen, eine Aktivität muss einige Daten in einer Online-Datenbank speichern. Die Aktivität
kann einen Companion-Dienst starten und die zu speichernden Daten bereitstellen, indem ein Intent an startService()
übergeben wird. Der Dienst empfängt den Intent in onStartCommand()
, stellt eine Verbindung zum Internet her und führt den
Datenbanktransaktion. Wenn die Transaktion abgeschlossen ist, wird der Dienst beendet und
zerstört.
Achtung:Ein Dienst wird im selben Prozess wie die Anwendung ausgeführt. in der es deklariert ist, und standardmäßig im Hauptthread dieser Anwendung. Wenn Ihr Dienst intensive oder blockierende Vorgänge ausführt, während der Nutzer mit einer Aktivität aus derselben verlangsamt die Aktivitätsleistung. Um Auswirkungen auf die Anwendung zu vermeiden einen neuen Thread im Dienst starten.
Die Klasse Service
ist die Basis
-Klasse für alle Dienste. Wenn Sie diesen Kurs erweitern, ist es wichtig, einen neuen Thread zu erstellen,
der Dienst seine gesamte Arbeit erledigen kann; verwendet der Dienst den Hauptthread Ihrer Anwendung,
das die Leistung jeglicher Aktivitäten verlangsamt, die Ihre Anwendung ausführt.
Das Android-Framework bietet auch die IntentService
von Service
, die einen
Worker-Thread verwenden, um alle Startanfragen nacheinander zu verarbeiten. Die Verwendung dieser Klasse ist nicht
empfohlen, da es ab Android 8 Oreo aufgrund der
Einführung von Beschränkungen für die Ausführung im Hintergrund.
Außerdem wird sie ab Android 11 eingestellt.
Sie können JobIntentService als
Ersatz für IntentService
, der mit neueren Android-Versionen kompatibel ist.
In den folgenden Abschnitten wird beschrieben, wie Sie Ihren eigenen benutzerdefinierten Dienst implementieren können. Sie sollten empfehlen wir Ihnen dringend, für die meisten Anwendungsfälle stattdessen WorkManager zu verwenden. Lesen Sie den Leitfaden zur Hintergrundverarbeitung auf Android-Geräten. um zu sehen, ob es eine Lösung gibt, die Ihren Anforderungen entspricht.
Service-Klasse erweitern
Sie können die Service
-Klasse erweitern
um jeden eingehenden Intent zu verarbeiten. Eine einfache Implementierung könnte wie folgt 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(); } }
Mit dem Beispielcode werden alle eingehenden Anrufe in onStartCommand()
verarbeitet.
und postet die Arbeit an eine Handler
, die 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 in einem Threadpool auszuführen, z. B. wenn Sie mehrere Anfragen gleichzeitig ausführen möchten.
Beachten Sie, dass die Methode onStartCommand()
Integer Die Ganzzahl ist ein Wert, der beschreibt, wie das System den Dienst im
wenn es vom System beendet wird. Der Rückgabewert
von onStartCommand()
muss einer der folgenden Werte sein:
Konstanten:
START_NOT_STICKY
- Wenn das System den Dienst beendet, nachdem
onStartCommand()
zurückgegeben wurde, erstellen Sie ihn nicht neu, es sei denn, es gibt ausstehende Intents zu liefern. Dies ist die sicherste Option, um die Ausführung Ihres Dienstes zu vermeiden, wenn er nicht erforderlich ist und Ihre Anwendung nicht abgeschlossene Jobs einfach neu starten kann. START_STICKY
- Wenn das System den Dienst beendet, nachdem
onStartCommand()
zurückgegeben wurde, erstellen Sie den Dienst neu und rufen SieonStartCommand()
auf. Stellen Sie den letzten Intent jedoch nicht noch einmal bereit. Stattdessen ruft das SystemonStartCommand()
mit einer Null Intent, es sei denn, es gibt ausstehende Intents zum Starten des Dienstes. In diesem Fall diese Intents zugestellt werden. Diese Option eignet sich für Mediaplayer (oder ähnliche Dienste), die ausgeführt werden, aber auf unbestimmte Zeit 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 SieonStartCommand()
mit dem letzten Intent auf, der an den . Alle ausstehenden Intents werden der Reihe nach zugestellt. Dies eignet sich für Dienste, die aktive Ausführung eines Jobs, der sofort fortgesetzt werden sollte, wie z. B. das Herunterladen einer Datei.
Weitere Informationen zu diesen Rückgabewerten finden Sie in der verlinkten Referenz. Dokumentation für jede Konstante.
Dienst starten
Sie können einen Dienst aus einer Aktivität oder einer anderen Anwendungskomponente aus starten, indem Sie
Intent
übergeben
auf startService()
oder startForegroundService()
. Die
Das Android-System ruft die Methode onStartCommand()
des Dienstes auf und übergibt ihr die Intent
.
mit dem angegeben wird, welcher Dienst gestartet werden soll.
Hinweis: Wenn Ihre App auf API-Level 26 oder höher ausgerichtet ist,
die Nutzung oder Erstellung von Hintergrunddiensten beschränkt, es sei denn, die App
selbst im Vordergrund zu sehen ist. Wenn eine App einen Dienst im Vordergrund erstellen muss,
sollte die App startForegroundService()
aufrufen. Diese Methode erstellt einen Hintergrunddienst,
signalisiert dem System, dass sich der Dienst selbst
im Vordergrund. Nachdem der Dienst erstellt wurde, muss er seinen
Methode startForeground()
innerhalb
5 Sekunden.
Beispielsweise kann eine Aktivität den Beispieldienst im vorherigen Abschnitt (HelloService
) mit einem expliziten Intent 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
ruft das Android-System die Methode onStartCommand()
des Dienstes auf. Wenn der Dienst nicht bereits ausgeführt wird, ruft das System zuerst onCreate()
auf und dann ruft es auf
onStartCommand()
.
Wenn der Dienst keine Bindung bereitstellt, ist der mit startService()
bereitgestellte Intent die einzige Kommunikationsart zwischen den
Anwendungskomponente und Dienst. Wenn Sie jedoch möchten, dass der Dienst ein Ergebnis zurücksendet,
kann der Client, der den Dienst startet, eine PendingIntent
für eine Übertragung erstellen.
(mit getBroadcast()
) und an den Dienst senden
in der Intent
, mit der der Dienst gestartet wird. Der Dienst kann dann die Methode
übertragen, um ein Ergebnis zu liefern.
Mehrere Anfragen zum Starten des Dienstes führen zu mehreren entsprechenden Aufrufen des
onStartCommand()
Allerdings muss nur eine Anfrage zum Beenden
Der Dienst (mit stopSelf()
oder stopService()
) ist erforderlich, um ihn zu beenden.
Dienst beenden
Ein gestarteter Dienst muss seinen eigenen Lebenszyklus verwalten. Das heißt, das System stoppt nicht
Dienst zu löschen, es sei denn, er muss den Systemspeicher und den Dienst wiederherstellen
wird weiterhin ausgeführt, nachdem onStartCommand()
zurückgegeben wurde. Die
Der Dienst muss sich selbst beenden, indem er stopSelf()
oder einen anderen Dienst aufruft.
-Komponente kann sie durch Aufrufen von stopService()
stoppen.
Sobald Sie das Beenden mit stopSelf()
oder stopService()
angefordert haben, wird der Dienst vom System gelöscht, sobald
möglich.
Wenn Ihr Dienst mehrere Anfragen an onStartCommand()
gleichzeitig verarbeitet, sollten Sie den
wenn Sie die Verarbeitung einer Startanfrage abgeschlossen haben, da Sie möglicherweise eine neue
start-Anfrage (Durch das Beenden der ersten Anfrage wird die zweite beendet). Um dies zu vermeiden
Problem beheben, können Sie mit stopSelf(int)
sicherstellen, dass Ihre Anfrage an
zum Beenden des Dienstes
basierend auf der letzten Startanfrage. Das heißt, wenn Sie stopSelf(int)
aufrufen, übergeben Sie die ID der Startanfrage (die startId
geliefert an onStartCommand()
), an die Ihr Stoppantrag gesendet wurde
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 vermeiden Sie eine Verschwendung von Systemressourcen und
Akkuleistung überprüfen, stellen Sie sicher, dass Ihre Anwendung die Dienste beendet, sobald sie fertig ist.
Bei Bedarf können andere Komponenten den Dienst anhalten, indem sie stopService()
aufrufen. Auch wenn Sie die Bindung
für den Dienst aktivieren,
Sie müssen den Dienst immer selbst beenden, wenn er einen Aufruf von onStartCommand()
erhält.
Weitere Informationen zum Lebenszyklus eines Dienstes finden Sie im Abschnitt Lebenszyklus eines Dienstes verwalten unten.
gebundenen Dienst erstellen
Bei einem gebundenen Dienst können Anwendungskomponenten sich an ihn binden. Dazu wird bindService()
aufgerufen, um eine dauerhafte Verbindung zu erstellen.
Komponenten können ihn im Allgemeinen nicht durch Aufrufen von startService()
starten.
Erstellen Sie einen gebundenen Dienst, wenn Sie mit dem Dienst aus Aktivitäten interagieren möchten und anderen Komponenten Ihrer Anwendung zu entfernen oder einige Funktionen Ihrer Anwendung für andere Anwendungen über Interprocess Communication (IPC) nutzen.
Implementieren Sie zum Erstellen eines gebundenen Dienstes die Callback-Methode onBind()
, um ein IBinder
-Objekt zurückzugeben, das
definiert die Schnittstelle für die Kommunikation mit dem Dienst. Andere Anwendungskomponenten können dann
bindService()
zum Abrufen der Schnittstelle und
Methoden für den Dienst aufrufen. Der Dienst kann nur die Anwendungskomponente bereitstellen,
an den Dienst gebunden ist. 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 bei einem Dienst,
begann bis onStartCommand()
.
Um einen gebundenen Dienst zu erstellen, müssen Sie die Schnittstelle definieren, die angibt, wie ein Client
mit dem Dienst kommunizieren können. Diese Schnittstelle zwischen dem Dienst
Ein Client muss eine Implementierung von IBinder
sein und ist das, was Ihr Dienst
von der Callback-Methode onBind()
zurückgegeben. Nachdem der Client die IBinder
erhalten hat, kann die Ausführung beginnen
über diese Schnittstelle mit dem Dienst interagieren.
Mehrere Clients können gleichzeitig an den Dienst gebunden werden. Wenn ein Kunde die Interaktion mit
den Dienst enthält, wird zum Aufheben der Bindung unbindService()
aufgerufen.
Wenn keine Clients an den Dienst gebunden sind, wird der Dienst vom System gelöscht.
Es gibt mehrere Möglichkeiten, einen gebundenen Dienst zu implementieren, und die Implementierung ist mehr als ein gestarteter Dienst. Aus diesen Gründen erscheint die Diskussion über gebundene Dienste in einer separates Dokument zu gebundenen Diensten.
Benachrichtigungen an den Nutzer senden
Wenn ein Dienst ausgeführt wird, kann er Nutzer mithilfe von Snackbar-Benachrichtigungen oder Benachrichtigungen in der Statusleiste über Ereignisse informieren.
Eine Snackbar-Benachrichtigung ist eine Nachricht, die nur für einen bestimmten Zeitraum kurz vor dem Verschwinden. Eine Benachrichtigung in der Statusleiste enthält ein Symbol mit einem Nachricht, die der Nutzer auswählen kann, um eine Aktion auszuführen (z. B. eine Aktivität zu starten).
Normalerweise ist eine Benachrichtigung in der Statusleiste das beste Verfahren für Hintergrundarbeiten wie eine Datei wurde heruntergeladen und der Nutzer kann diese nun bearbeiten. Wenn Nutzende die Benachrichtigung in der erweiterten Ansicht auswählt, kann durch die Benachrichtigung eine Aktivität gestartet werden. um beispielsweise die heruntergeladene Datei anzuzeigen.
Lebenszyklus eines Dienstes verwalten
Der Lebenszyklus eines Dienstes ist viel einfacher als der einer Aktivität. Es ist jedoch noch mehr Achten Sie genau darauf, wie Ihr Dienst erstellt und zerstört wird, kann der Dienst im Hintergrund ausgeführt werden, ohne dass der Nutzer es merkt.
Der Lebenszyklus eines Dienstes – vom Erstellen bis zum Löschen – kann einer dieser beiden Pfade:
- Ein gestarteter Dienst
Der Dienst wird erstellt, wenn eine andere Komponente
startService()
aufruft. Der Dienst wird dann auf unbestimmte Zeit ausgeführt und muss indem SiestopSelf()
aufrufen. Auch eine andere Komponente kann indem dustopService()
aufrufst. Wenn der Dienst angehalten 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 mit dem Dienst. über eineIBinder
-Schnittstelle. Der Client kann die Verbindung durch Aufrufen vonunbindService()
Bindung für mehrere Clients möglich und wenn sie die Bindung aufheben, zerstört das System den Dienst. Dienst muss sich nicht selbst stoppen.
Diese beiden Pfade sind nicht völlig getrennt. Sie können eine Bindung an einen Dienst erstellen, der bereits
begann mit startService()
. So können Sie zum Beispiel
starte einen Hintergrundmusikdienst, indem du startService()
mit einer Intent
aufrufst, die die Musik identifiziert, die abgespielt werden soll. Später
z. B. wenn der Nutzer eine gewisse Kontrolle über den Player ausüben oder Informationen zum
aktuellen Titel enthält, kann eine Aktivität durch Aufrufen von bindService()
an den Dienst gebunden werden. In solchen Fällen beendet stopService()
oder stopSelf()
den Dienst erst, 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 vornehmen und die Arbeit zur richtigen Zeit ausführen. Das folgende Skeleton: Dienst veranschaulicht 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 funonCreate
() { // The service is being created } override funonStartCommand
(intent: Intent?, flags: Int, startId: Int): Int { // The service is starting, due to a call to startService() return startMode } override funonBind
(intent: Intent): IBinder? { // A client is binding to the service with bindService() return binder } override funonUnbind
(intent: Intent): Boolean { // All clients have unbound with unbindService() return allowRebind } override funonRebind
(intent: Intent) { // A client is binding to the service with bindService(), // after onUnbind() has already been called } override funonDestroy
() { // The service is no longer used and is being destroyed } }
Java
public class ExampleService extends Service { int startMode; // indicates how to behave if the service is killed IBinder binder; // interface for clients that bind boolean allowRebind; // indicates whether onRebind should be used @Override public voidonCreate
() { // The service is being created } @Override public intonStartCommand
(Intent intent, int flags, int startId) { // The service is starting, due to a call tostartService()
return startMode; } @Override public IBinderonBind
(Intent intent) { // A client is binding to the service withbindService()
return binder; } @Override public booleanonUnbind
(Intent intent) { // All clients have unbound withunbindService()
return allowRebind; } @Override public voidonRebind
(Intent intent) { // A client is binding to the service withbindService()
, // after onUnbind() has already been called } @Override public voidonDestroy
() { // The service is no longer used and is being destroyed } }
Hinweis: Im Gegensatz zu den Callback-Methoden für den Aktivitätslebenszyklus nicht erforderlich, die Implementierung der Basisklasse dieser Callback-Methoden aufzurufen.
In Abbildung 2 sind die typischen Callback-Methoden für einen Dienst dargestellt. Obwohl die Abbildung trennt
Dienste, die von startService()
erstellt werden,
erstellt von bindService()
, behalten
Beachten Sie, dass jeder Dienst unabhängig von seinem Start potenziell
Clients ermöglichen kann, sich an ihn zu binden.
Dienst, der ursprünglich mit onStartCommand()
gestartet wurde (durch einen Client, der startService()
aufruft)
kann trotzdem einen Anruf an onBind()
empfangen (wenn ein Client anruft,
bindService()
.
Durch die Implementierung dieser Methoden können Sie diese beiden verschachtelten Schleifen des Dienstes Lebenszyklus:
- Die gesamte Lebensdauer eines Dienstes liegt zwischen dem Zeitpunkt, zu dem
onCreate()
aufgerufen wird, und dem Zeitpunkt, zu demonDestroy()
zurückgegeben wird. Wie eine Aktivität führt auch ein Dienst die ErsteinrichtungonCreate()
und gibt alle verbleibenden Ressourcen inonDestroy()
frei. Beispiel: Der Musikwiedergabedienst kann den Thread erstellen, in dem die Musik inonCreate()
abgespielt wird, und ihn dann inonDestroy()
beenden.Hinweis: Das
onCreate()
undonDestroy()
werden für alle Dienste aufgerufen, unabhängig davon, ob sie werden vonstartService()
oderbindService()
erstellt. - Die aktive Lebensdauer eines Dienstes beginnt mit einem Aufruf von
onStartCommand()
oderonBind()
. Jeder Methode wird dasIntent
übergeben, das entweder anstartService()
oderbindService()
übergeben wurde.Wenn der Dienst gestartet wird, endet die aktive Lebensdauer zur selben Zeit wie die gesamte Lebensdauer. endet. Der Dienst ist auch dann noch aktiv, wenn
onStartCommand()
zurückgegeben wird. Wenn der Dienst gebunden ist, endet die aktive Lebensdauer, wennonUnbind()
zurückgegeben wird.
Hinweis:Obwohl ein gestarteter Dienst durch einen Aufruf der
stopSelf()
oder stopService()
ist, gibt es keinen entsprechenden Callback für die
-Dienst (es gibt keinen onStop()
-Callback). Wenn der Dienst nicht
an einen Client gebunden ist,
Sie wird vom System gelöscht, wenn der Dienst beendet wird. onDestroy()
ist der einzige empfangene Rückruf.
Weitere Informationen zum Erstellen eines Dienstes, der eine Bindung bereitstellt, finden Sie im Dokument Bound Services.
mit weiteren Informationen zum onRebind()
im Abschnitt über die Verwaltung des Lebenszyklus
ein gebundener Dienst.