Überblick über die Dienste

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 von stopSelf() oder stopService() 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 ein IBinder 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() oder onBind(). 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 Sie onStartCommand() auf. Stellen Sie den letzten Intent jedoch nicht noch einmal bereit. Stattdessen ruft das System onStartCommand() 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 Sie onStartCommand() 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 Sie stopSelf() aufrufen. Auch eine andere Komponente kann indem du stopService() 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 eine IBinder-Schnittstelle. Der Client kann die Verbindung durch Aufrufen von unbindService() 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 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 nicht erforderlich, die Implementierung der Basisklasse dieser Callback-Methoden aufzurufen.

Abbildung 2: Der Lebenszyklus des Dienstes. Im Diagramm auf der linken Seite zeigt den Lebenszyklus, wenn der Dienst mit startService() erstellt wurde. Das Diagramm rechts zeigt den Lebenszyklus, wenn der Dienst erstellt wird. mit bindService().

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 dem onDestroy() zurückgegeben wird. Wie eine Aktivität führt auch ein Dienst die Ersteinrichtung onCreate() und gibt alle verbleibenden Ressourcen in onDestroy() frei. Beispiel: Der Musikwiedergabedienst kann den Thread erstellen, in dem die Musik in onCreate() abgespielt wird, und ihn dann in onDestroy() beenden.

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

  • Die aktive Lebensdauer eines Dienstes beginnt mit einem Aufruf von onStartCommand() oder onBind(). Jeder Methode wird das Intent übergeben, das entweder an startService() oder bindService() ü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, wenn onUnbind() 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.