Wie überprüfe ich, ob ein Hintergrunddienst ausgeführt wird?
Ich möchte eine Android-Aktivität, die den Status des Dienstes umschaltet. Mit dieser Funktion kann ich sie aktivieren, wenn sie deaktiviert ist, und deaktivieren, wenn sie aktiviert ist.
android
android-service
Biene
quelle
quelle
getRunningTasks()
, wird es wahrscheinlich sein.Antworten:
Ich hatte vor kurzem das gleiche Problem. Da mein Dienst lokal war, habe ich einfach ein statisches Feld in der Dienstklasse verwendet, um den Status umzuschalten, wie hier von hackbod beschrieben
EDIT (für die Aufzeichnung):
Hier ist die von Hackbod vorgeschlagene Lösung:
quelle
onDestroy()
wird nicht aufgerufen. Daher kann die statische Variable in einem solchen Szenario nicht aktualisiert werden, was zu inkonsistentem Verhalten führt.Ich verwende Folgendes innerhalb einer Aktivität:
Und ich nenne es mit:
Dies funktioniert zuverlässig, da es auf den Informationen zum Ausführen von Diensten basiert, die vom Android-Betriebssystem über ActivityManager # getRunningServices bereitgestellt werden .
Alle Ansätze, die onDestroy- oder onSometing-Ereignisse oder Ordner oder statische Variablen verwenden, funktionieren nicht zuverlässig, da Sie als Entwickler nie wissen, wann Android Ihren Prozess beendet oder welche der genannten Rückrufe aufgerufen werden oder nicht. Bitte beachten Sie die Spalte "killable" in der Lifecycle-Ereignistabelle in der Android-Dokumentation.
quelle
getRunningServices
veraltet. Diese Antwort benötigt ein Update für eine neuere Version.Ich habs!
Sie MÜSSEN anrufen,
startService()
damit Ihr Dienst ordnungsgemäß registriert wird und das BestehenBIND_AUTO_CREATE
nicht ausreicht.Und jetzt die ServiceTools-Klasse:
quelle
Eine kleine Ergänzung ist:
Mein Ziel ist es zu wissen, ob ein Dienst ausgeführt wird, ohne ihn tatsächlich auszuführen, wenn er nicht ausgeführt wird.
Das Aufrufen von bindService oder das Aufrufen einer Absicht, die vom Dienst abgefangen werden kann, ist dann keine gute Idee, da der Dienst gestartet wird, wenn er nicht ausgeführt wird.
Wie miracle2k vorgeschlagen hat, ist es am besten, ein statisches Feld in der Serviceklasse zu haben, um zu wissen, ob der Service gestartet wurde oder nicht.
Um es noch sauberer zu machen, schlage ich vor, den Dienst in einen Singleton mit einem sehr sehr faulen Abruf umzuwandeln: Das heißt, es gibt überhaupt keine Instanziierung der Singleton- Instanz durch statische Methoden. Die statische getInstance-Methode Ihres Dienstes / Singletons gibt nur die Instanz des Singletons zurück, wenn dieser erstellt wurde. Der Singleton selbst wird jedoch nicht gestartet oder instanziiert. Der Dienst wird nur über normale Dienststartmethoden gestartet.
Es wäre dann noch sauberer, das Singleton-Entwurfsmuster zu ändern, um die verwirrende getInstance-Methode in so etwas wie die
isInstanceCreated() : boolean
Methode umzubenennen .Der Code sieht folgendermaßen aus:
Diese Lösung ist elegant, aber nur relevant, wenn Sie Zugriff auf die Serviceklasse haben und nur für Klassen neben der App / dem Paket des Service. Wenn sich Ihre Klassen außerhalb der Service-App / des Service-Pakets befinden, können Sie den ActivityManager mit den von Pieter-Jan Van Robays unterstrichenen Einschränkungen abfragen.
quelle
Sie können dies verwenden (ich habe es noch nicht versucht, aber ich hoffe, dass es funktioniert):
Die startService-Methode gibt ein ComponentName-Objekt zurück, wenn bereits ein Dienst ausgeführt wird. Wenn nicht, wird null zurückgegeben.
Siehe public abstract ComponentName startService (Absichtsdienst) .
Dies ist nicht wie eine Überprüfung, denke ich, weil es den Dienst startet, so dass Sie
stopService(someIntent);
unter dem Code hinzufügen können .quelle
if(startService(someIntent) != null)
überprüft wird,IsserviceRunning
aber auch ein neuer Dienst abgespielt wird.quelle
Ein Auszug aus Android- Dokumenten:
Stellen Sie sich diesen Hack als "Ping" vor
Service
. Da wir synchron senden können, können wir synchron über den UI-Thread senden und ein Ergebnis erhalten .Service
Activity
Der Gewinner in vielen Anwendungen ist natürlich ein statisches boolesches Feld im Dienst, das auf
true
inService.onCreate()
und auffalse
in gesetzt ist,Service.onDestroy()
weil es viel einfacher ist.quelle
Ich habe eine der oben vorgestellten Lösungen leicht modifiziert, aber die Klasse anstelle eines generischen Zeichenfolgennamens übergeben, um sicherzugehen, dass Zeichenfolgen verglichen werden, die aus derselben Methode stammen
class.getName()
und dann
quelle
Class<? extends Service>
Der richtige Weg, um zu überprüfen, ob ein Dienst ausgeführt wird, besteht darin, ihn einfach zu fragen. Implementieren Sie einen BroadcastReceiver in Ihrem Dienst, der auf Pings aus Ihren Aktivitäten reagiert. Registrieren Sie den BroadcastReceiver, wenn der Dienst gestartet wird, und heben Sie die Registrierung auf, wenn der Dienst zerstört wird. Senden Sie aus Ihrer Aktivität (oder einer beliebigen Komponente) eine lokale Broadcast- Absicht an den Dienst. Wenn dieser antwortet, wissen Sie, dass er ausgeführt wird. Beachten Sie den subtilen Unterschied zwischen ACTION_PING und ACTION_PONG im folgenden Code.
quelle
Ich möchte der Antwort von @Snicolas nur eine Notiz hinzufügen. Mit den folgenden Schritten können Sie den Stoppdienst mit / ohne Anruf überprüfen
onDestroy()
.onDestroy()
aufgerufen: Gehen Sie zu Einstellungen -> Anwendung -> Ausführen von Diensten -> Wählen Sie Ihren Dienst aus und beenden Sie ihn.onDestroy()
nicht aufgerufen: Gehen Sie zu Einstellungen -> Anwendung -> Anwendungen verwalten -> Wählen Sie Ihre Anwendung aus, in der Ihr Dienst ausgeführt wird, und klicken Sie auf "Stopp erzwingen". Da Ihre Anwendung hier jedoch gestoppt wird, werden definitiv auch die Dienstinstanzen gestoppt.Abschließend möchte ich erwähnen, dass der dort erwähnte Ansatz, bei dem eine statische Variable in der Singleton-Klasse verwendet wird, für mich funktioniert.
quelle
onDestroy
wird nicht immer im Service angerufen, das ist also nutzlos!Beispiel: Führen Sie die App mit einer Änderung von Eclipse erneut aus. Die Anwendung wird mit SIG: 9 zwangsweise beendet.
quelle
Zunächst sollten Sie nicht versuchen, den Dienst mit dem ActivityManager zu erreichen. (Diskutiert hier )
Dienste können eigenständig ausgeführt werden, an eine Aktivität gebunden sein oder beides. Sie können eine Aktivität einchecken, wenn Ihr Dienst ausgeführt wird oder nicht, indem Sie eine Schnittstelle (die Binder erweitert) erstellen, in der Sie Methoden deklarieren, die sowohl die Aktivität als auch der Dienst verstehen. Sie können dies tun, indem Sie eine eigene Schnittstelle erstellen, in der Sie beispielsweise "isServiceRunning ()" deklarieren. Sie können dann Ihre Aktivität an Ihren Dienst binden, die Methode isServiceRunning () ausführen, der Dienst prüft selbst, ob sie ausgeführt wird oder nicht, und gibt einen Booleschen Wert an Ihre Aktivität zurück.
Sie können diese Methode auch verwenden, um Ihren Dienst zu beenden oder auf andere Weise mit ihm zu interagieren.
In diesem Tutorial habe ich gelernt, wie dieses Szenario in meiner Anwendung implementiert wird.
quelle
Wieder eine andere Alternative, die Menschen möglicherweise sauberer finden, wenn sie ausstehende Absichten verwenden (zum Beispiel mit
AlarmManager
:Wo
CODE
ist eine Konstante, die Sie privat in Ihrer Klasse definieren, um die ausstehenden Absichten zu identifizieren, die Ihrem Service zugeordnet sind.quelle
Unten ist ein eleganter Hack, der alle abdeckt
Ifs
. Dies gilt nur für lokale Dienste.Und später:
quelle
Xamarin C # -Version:
quelle
GetSystemService
.Für den hier angegebenen Anwendungsfall können wir einfach
stopService()
den Rückgabewert der Methode verwenden. Es wird zurückgegeben,true
wenn der angegebene Dienst vorhanden ist und beendet wird. Sonst kehrt es zurückfalse
. Sie können den Dienst also neu starten, wenn das Ergebnisfalse
anders ist. Es wird sichergestellt, dass der aktuelle Dienst gestoppt wurde. :) Es wäre besser, wenn Sie einen Blick auf haben diese .quelle
Ein anderer Ansatz mit Kotlin. Inspiriert von den Antworten anderer Benutzer
Als Kotlin-Erweiterung
Verwendungszweck
quelle
In kotlin können Sie eine boolesche Variable in das Begleitobjekt einfügen und deren Wert aus einer beliebigen Klasse überprüfen:
Ändern Sie den Wert, wenn der Dienst erstellt und zerstört wird
quelle
Verwenden Sie in Ihrer Service-Unterklasse einen statischen Booleschen Wert, um den Status des Service abzurufen, wie unten gezeigt.
MyService.kt
MainActivity.kt
quelle
Für Kotlin können Sie den folgenden Code verwenden.
quelle
Der Anruf
quelle
ActivityManager.getRunningServices
ist seit Android OEs kann mehrere Dienste mit demselben Klassennamen geben.
Ich habe gerade zwei Apps erstellt. Der Paketname der ersten App lautet
com.example.mock
. Ich habe ein Unterpaket erstellt, daslorem
in der App aufgerufen wurde, und einen Dienst namensMock2Service
. Sein voll qualifizierter Name ist alsocom.example.mock.lorem.Mock2Service
.Dann habe ich die zweite App und einen Dienst namens erstellt
Mock2Service
. Der Paketname der zweiten App lautetcom.example.mock.lorem
. Der vollqualifizierte Name des Dienstes istcom.example.mock.lorem.Mock2Service
ebenfalls.Hier ist meine Logcat-Ausgabe.
Eine bessere Idee ist zu vergleichen
ComponentName
Fällen wegenequals()
derComponentName
beiden Paketnamen und Klassennamen vergleicht. Auf einem Gerät können nicht zwei Apps mit demselben Paketnamen installiert sein.Die Methode equals () von
ComponentName
.Komponentenname
quelle
Bitte benutzen Sie diesen Code.
quelle
Dies gilt eher für das Debuggen von Intent-Diensten, da sie einen Thread erzeugen, aber möglicherweise auch für reguläre Dienste funktionieren. Ich habe diesen Thread dank Binging gefunden
In meinem Fall habe ich mit dem Debugger herumgespielt und die Thread-Ansicht gefunden. Es sieht aus wie das Aufzählungszeichen in MS Word. Wie auch immer, Sie müssen sich nicht im Debugger-Modus befinden, um es zu verwenden. Klicken Sie auf den Prozess und dann auf diese Schaltfläche. Alle Intent Services werden angezeigt, während sie ausgeführt werden, zumindest auf dem Emulator.
quelle
Wenn der Dienst zu einem anderen Prozess oder APK gehört, verwenden Sie die auf dem ActivityManager basierende Lösung.
Wenn Sie Zugriff auf die Quelle haben, verwenden Sie einfach die Lösung basierend auf einem statischen Feld. Stattdessen würde ich die Verwendung eines Booleschen Werts vorschlagen. Während der Dienst ausgeführt wird, aktualisieren Sie einfach seinen Wert auf "Jetzt" und setzen Sie ihn nach Abschluss auf "Null". Anhand der Aktivität können Sie überprüfen, ob sie null ist oder das Datum zu alt ist, was bedeutet, dass sie nicht ausgeführt wird.
Sie können auch eine Broadcast-Benachrichtigung von Ihrem Dienst senden, die angibt, dass weitere Informationen wie der Fortschritt ausgeführt werden.
quelle
In TheServiceClass definieren Sie:
Dann In onStartCommand (...)
Rufen Sie dann
if(TheServiceClass.serviceRunning == true)
aus einer beliebigen Klasse an.quelle
stopService
. Zumindest für Intent-Services.onDestroy()
wird sofort angerufen,onHandleIntent()
läuft aber nocheinfache Verwendung binden mit nicht automatisch erstellen- siehe ps. und aktualisieren ...Beispiel:
warum nicht verwenden? getRunningServices ()
Hinweis: Diese Methode ist nur zum Debuggen oder Implementieren von Benutzeroberflächen vom Typ Service Management vorgesehen.
ps. Android-Dokumentation ist irreführend Ich habe ein Problem auf Google Tracker geöffnet, um alle Zweifel zu beseitigen:
https://issuetracker.google.com/issues/68908332
Wie wir sehen können, ruft der Bindedienst tatsächlich eine Transaktion über den ActivityManager-Ordner über die Service-Cache-Ordner auf. Ich verfolge nicht, welcher Dienst für die Bindung verantwortlich ist, aber wie wir sehen können, lautet das Ergebnis für die Bindung:
Transaktion erfolgt über Ordner:
Nächster:
Dies wird in ActivityThread festgelegt über:
Dies wird in ActivityManagerService in der Methode aufgerufen:
dann:
aber es gibt keine "Aktivität" nur Fensterpaket und Alarm ..
Also müssen wir zurückrufen, um anzurufen:
Dies macht Anruf durch:
was dazu führt :
und das ist native Methode ....
Ich habe jetzt keine Zeit, mich in c zu vertiefen. Bis ich den Restanruf seziere, setze ich meine Antwort aus.
Der beste Weg, um zu überprüfen, ob der Dienst ausgeführt wird, besteht darin, eine Bindung zu erstellen (wenn die Bindung nicht erstellt wurde, existiert kein Dienst) - und den Dienst über die Bindung nach seinem Status abzufragen (unter Verwendung des gespeicherten internen Flags für den Status).
Update 23.06.2018
Ich fand die interessant:
Zusamenfassend :)
"Stellen Sie einen Ordner für einen bereits gebundenen Dienst bereit. Diese Methode ist synchron und startet den Zieldienst nicht, wenn er nicht vorhanden ist."
public IBinder peekService (Intent Service, String ResolutionedType, String Calling Package) löst eine RemoteException aus.
quelle
Meine Kotlin-Konvertierung der
ActivityManager::getRunningServices
basierten Antworten. Fügen Sie diese Funktion in eine Aktivität ein.quelle
Sie können diese Optionen in den Android Developer-Optionen verwenden, um festzustellen, ob Ihr Dienst noch im Hintergrund ausgeführt wird.
quelle
Nimm es ruhig Jungs ... :)
Ich denke, die am besten geeignete Lösung besteht darin, ein Schlüssel-Wert-Paar
SharedPreferences
zu halten, ob der Dienst ausgeführt wird oder nicht.Die Logik ist sehr klar; an jeder gewünschten Position in Ihrer Serviceklasse; Setzen Sie einen booleschen Wert, der als Flag für Sie dient, ob der Dienst ausgeführt wird oder nicht. Lesen Sie diesen Wert dann an einer beliebigen Stelle in Ihrer Anwendung.
Ein Beispielcode, den ich in meiner App verwende, ist unten:
In meiner Service-Klasse (Ein Service für Audio Stream) führe ich den folgenden Code aus, wenn der Service aktiv ist.
In jeder Aktivität meiner Anwendung überprüfe ich dann den Status des Dienstes mithilfe des folgenden Codes.
Keine besonderen Berechtigungen, keine Schleifen ... Einfacher Weg, saubere Lösung :)
Wenn Sie zusätzliche Informationen benötigen, klicken Sie bitte auf den Link
Hoffe das hilft.
quelle
onDestroy
wird nicht immer aufgerufen, wenn der Dienst beendet wird. Zum Beispiel habe ich gesehen, dass meine Dienste in Situationen mit wenig Arbeitsspeicher getötet wurden, ohneonDestroy
angerufen zu werden.