1061 Stimmen

Wie prüft man, ob ein Dienst auf Android läuft?

Wie kann ich überprüfen, ob ein Hintergrunddienst läuft?

Ich möchte eine Android-Aktivität, die den Status des Dienstes umschaltet - ich kann ihn einschalten, wenn er ausgeschaltet ist, und ausschalten, wenn er eingeschaltet ist.

2 Stimmen

Überprüfen Sie dieser deutsche Leitfaden .

23 Stimmen

Die richtige Antwort steht unten und nicht die markierte: stackoverflow.com/a/5921190/2369122

2 Stimmen

@toidiu Wenn das nicht schon nerfed worden ist wie getRunningTasks() dann wird es wahrscheinlich so sein.

1793voto

geekQ Punkte 28189

Ich verwende das Folgende innerhalb einer Aktivität:

private boolean isMyServiceRunning(Class<?> serviceClass) {
    ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if (serviceClass.getName().equals(service.service.getClassName())) {
            return true;
        }
    }
    return false;
}

Und ich nenne es nutzen:

isMyServiceRunning(MyService.class)

Dies funktioniert zuverlässig, da es auf den Informationen über laufende Dienste basiert, die vom Android-Betriebssystem über ActivityManager#getRunningServices .

Alle Ansätze, die onDestroy- oder onSometing-Ereignisse oder Binder oder statische Variablen verwenden, werden nicht zuverlässig funktionieren, da man als Entwickler nie weiß, wann Android sich entscheidet, den Prozess zu beenden oder welche der genannten Callbacks aufgerufen werden oder nicht. Bitte beachten Sie die Spalte "killable" in der Tabelle der Lebenszyklusereignisse in der Android-Dokumentation.

0 Stimmen

Vermutlich ist dafür die Berechtigung erforderlich, laufende Anwendungen und Dienste anzuzeigen? Nicht ideal.

92 Stimmen

Vielen Dank für diese Lösung. Ich möchte hinzufügen: Statt "com.example.MyService" ist es eleganter, MyService.class.getName() zu verwenden.

0 Stimmen

ACTIVITY_SERVICE ist in Eclipse für die API 10 nicht definiert. Habe ich etwas übersehen?

316voto

miracle2k Punkte 25301

Ich hatte vor nicht allzu langer Zeit das gleiche Problem. Da mein Dienst lokal war, endete ich einfach mit einem statischen Feld in der Serviceklasse, um den Zustand umzuschalten, wie von Hackbod beschrieben aquí

EDIT (für das Protokoll):

Hier ist die von hackbod vorgeschlagene Lösung:

Wenn Ihr Client- und Servercode Teil der gleichen .apk ist und Sie mit einem konkreten Intent an den Dienst binden (einer, der die Dienstklasse spezifiziert), dann können Sie einfach Ihren Dienst eine globale Variable setzen lassen, die Ihr Client überprüfen kann, wenn er läuft.

Wir haben absichtlich keine API, um zu prüfen, ob ein Dienst läuft, denn wenn man so etwas tun will, landet man fast immer wenn Sie so etwas tun wollen, enden Sie mit Race Conditions in Ihrem Code.

0 Stimmen

Dies wird schneller ausgeführt als die Antwort von @geekQ (jetzt die am höchsten bewertete), aber ich frage mich, ob der Verweis auf den Service dazu führt, dass diese Klasse in die Receiver-Komponente aufgenommen wird - die so klein wie möglich gehalten werden sollte.

33 Stimmen

@Pacerier, die Lösung, auf die Sie verweisen, erfordert den Start des Dienstes, und ich denke, die beste flexible Lösung sollte es Ihnen ermöglichen, zu überprüfen, ob ein Dienst läuft, ohne ihn zu starten.

0 Stimmen

+1 Diese Methode ist nachhaltiger. Die von @geekQ angebotene Methode funktioniert nicht unter Android KitKat.

81voto

Kevin Parker Punkte 16483

Ich hab's!

Sie MUSS aufrufen startService() damit Ihr Dienst ordnungsgemäß registriert und zugelassen wird BIND_AUTO_CREATE reicht nicht aus.

Intent bindIntent = new Intent(this,ServiceTask.class);
startService(bindIntent);
bindService(bindIntent,mConnection,0);

Und nun die Klasse ServiceTools:

public class ServiceTools {
    private static String LOG_TAG = ServiceTools.class.getName();

    public static boolean isServiceRunning(String serviceClassName){
        final ActivityManager activityManager = (ActivityManager)Application.getContext().getSystemService(Context.ACTIVITY_SERVICE);
        final List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);

        for (RunningServiceInfo runningServiceInfo : services) {
            if (runningServiceInfo.service.getClassName().equals(serviceClassName)){
                return true;
            }
        }
        return false;
     }
}

0 Stimmen

Hier werden doch nur die Systemdienste aufgelistet, oder?! Also ist mein lokaler Dienst von der Liste ausgeschlossen und ich bekomme false ;(

0 Stimmen

Das funktioniert bei externen Diensten, bei lokalen Diensten ist es ziemlich offensichtlich, wenn man sie laufen lässt.

12 Stimmen

Tut mir leid, aber ich muss sagen, dass das eine sehr dumme Antwort ist Warum ist das so offensichtlich?!

66voto

Snicolas Punkte 37333

Eine kleine Ergänzung ist:

Mein Ziel ist es, zu wissen, ob ein Dienst läuft, ohne ihn tatsächlich zu starten, wenn er nicht läuft.

Der Aufruf von bindService oder der Aufruf eines Intents, der vom Dienst abgefangen werden kann, ist keine gute Idee, da der Dienst gestartet wird, wenn er nicht läuft.

Wie miracle2k vorschlug, ist es daher am besten, ein statisches Feld in der Dienstklasse zu haben, um zu wissen, ob der Dienst gestartet wurde oder nicht.

Um es noch sauberer zu machen, schlage ich vor, den Dienst in ein Singleton mit einem sehr trägen Abruf umzuwandeln: Das heißt, es gibt überhaupt keine Instanziierung der Einzelperson Instanz durch statische Methoden. Die statische getInstance-Methode Ihres Dienstes/Singletons gibt nur die Instanz des Singletons zurück, wenn es erstellt wurde. Aber sie startet oder instanziiert das Singleton selbst nicht. Der Dienst wird nur über die normalen Startmethoden des Dienstes gestartet.

Es wäre dann noch sauberer, das Singleton-Entwurfsmuster zu ändern und die verwirrende getInstance-Methode in etwas wie isInstanceCreated() : boolean Methode.

Der Code wird wie folgt aussehen:

public class MyService extends Service
{
   private static MyService instance = null;

   public static boolean isInstanceCreated() {
      return instance != null;
   }//met

   @Override
   public void onCreate()
   {
      instance = this;
      ....
   }//met

   @Override
   public void onDestroy()
   {
      instance = null;
      ...
   }//met
}//class

Diese Lösung ist elegant, aber sie ist nur relevant, wenn Sie Zugriff auf die Dienstklasse haben, und nur für Klassen außerhalb der Anwendung/des Pakets des Dienstes. Wenn Ihre Klassen außerhalb der Dienstanwendung/des Dienstpakets liegen, können Sie den ActivityManager mit den von Pieter-Jan Van Robays hervorgehobenen Einschränkungen abfragen.

43 Stimmen

Dies ist fehlerhaft. onDestroy wird nicht garantiert aufgerufen.

0 Stimmen

Warum nicht, jemand muss immer noch stop aufrufen, um einen Dienst zu stoppen, und das führt dazu, dass onDestroy aufgerufen wird.

10 Stimmen

Wenn das System auf Speicher niedrig ist, wird Ihr Dienst automatisch ohne einen Aufruf Ihrer onDestroy beendet werden, weshalb ich sage, dass dies fehlerhaft ist.

30voto

Keenan Gebze Punkte 1231

Sie können dies verwenden (ich habe es noch nicht ausprobiert, aber ich hoffe, es funktioniert):

if(startService(someIntent) != null) {
    Toast.makeText(getBaseContext(), "Service is already running", Toast.LENGTH_SHORT).show();
}
else {
    Toast.makeText(getBaseContext(), "There is no service running, starting service..", Toast.LENGTH_SHORT).show();
}

Die startService-Methode gibt ein ComponentName-Objekt zurück, wenn es bereits einen laufenden Dienst gibt. Wenn nicht, wird null zurückgegeben.

参照 public abstract ComponentName startService (Intent service) .

Dies ist nicht wie eine Überprüfung, denn es startet den Dienst, so dass Sie die stopService(someIntent); unter dem Kodex.

14 Stimmen

Das ist nicht ganz das, was in den Unterlagen steht. Laut Ihrem Link: "Rückgabe Wenn der Dienst gestartet wird oder bereits läuft, wird der Komponentenname des tatsächlich gestarteten Dienstes zurückgegeben; andernfalls, wenn der Dienst nicht existiert, wird null zurückgegeben."

0 Stimmen

Netter Gedanke ... passt aber nicht zur aktuellen Situation.

6 Stimmen

Das ist nicht der richtige Weg, denn wenn die IDE auslöst if(startService(someIntent) != null) die prüft, ob IsserviceRunning aber das wird auch neue Dienste spielen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X