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


Wie überprüfe ich, ob ein Hintergrunddienst (auf Android) läuft?

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


794
2018-03-01 18:09


Ursprung


Antworten:


Ich hatte das gleiche Problem vor nicht allzu langer Zeit. Da mein Dienst lokal war, benutzte ich einfach ein statisches Feld in der Dienstklasse, um den Status umzuschalten, wie von hackbod beschrieben Hier

EDIT (für den Datensatz):

Hier ist die von Hackbock vorgeschlagene Lösung:

Wenn Ihr Client- und Servercode Teil derselben .apk-Datei ist, und Sie sind   Bindung an den Dienst mit einer konkreten Absicht (eine, die die angibt   Genaue Serviceklasse), dann können Sie einfach Ihren Service einstellen lassen   globale Variable, wenn sie ausgeführt wird, die Ihr Client überprüfen kann.

Wir haben bewusst keine API, um zu prüfen, ob ein Service ist   läuft, weil fast ohne Fehler, wenn Sie etwas tun wollen   So hast du am Ende die Rennbedingungen in deinem Code.


248
2018-03-03 22:58



Ich benutze Folgendes aus einer Aktivität heraus:

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 mit:

isMyServiceRunning(MyService.class)

Dies funktioniert zuverlässig, da es auf den Informationen über das Ausführen von Diensten basiert, die von dem Betriebssystem Android bereitgestellt werden ActivityManager # getRunningServices.

Alle Ansätze, die onDestroy oder onSomething Events oder Binders oder statische Variablen verwenden, funktionieren nicht zuverlässig, da Sie als Entwickler nie wissen, wann Android entscheidet, Ihren Prozess zu beenden oder welche der genannten Callbacks aufgerufen werden oder nicht. Bitte beachten Sie die Spalte "killable" in der Lebenszyklus-Ereignistabelle in der Android-Dokumentation.


1518
2018-05-07 12:54



Ich habs!

Sie MUSS Anruf startService() damit Ihre Dienstleistung ordnungsgemäß registriert und weitergegeben wird BIND_AUTO_CREATE wird nicht ausreichen.

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

Und jetzt die ServiceTools-Klasse:

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;
     }
}

67
2018-02-12 04:42



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 keine gute Idee, da der Dienst gestartet wird, wenn er nicht ausgeführt wird.

Wie von miracle2k vorgeschlagen, ist es am besten, ein statisches Feld in der Serviceklasse zu haben, um zu wissen, ob der Dienst gestartet wurde oder nicht.

Um es noch sauberer zu machen, schlage ich vor, den Dienst in einem Singleton mit einem sehr sehr faulen Abruf zu transformieren: das heißt, es gibt überhaupt keine Instanziierung Singleton Instanz durch statische Methoden. Die statische getInstance-Methode Ihres Service / Singleton gibt nur die Instanz des Singletons zurück, wenn sie erstellt wurde. Aber es startet oder instanziiert das Singleton selbst nicht. Der Dienst wird nur über normale Dienststartmethoden gestartet.

Es wäre dann noch sauberer, das Singleton-Designmuster zu modifizieren, um die verwirrende getInstance-Methode in etwas Ähnliches umzubenennen isInstanceCreated() : boolean Methode.

Der Code sieht folgendermaßen aus:

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 nur relevant, wenn Sie Zugriff auf die Serviceklasse haben und nur für Klassen die App / das Paket des Dienstes. 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.


51
2018-05-20 10:58



Du kannst das benutzen (ich habe das noch nicht versucht, aber ich hoffe, das 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 bereits ein Service ausgeführt wird. Wenn nicht, wird null zurückgegeben.

Sehen public abstract Komponentenname startService (Intent-Dienst).

Das ist nicht wie eine Überprüfung, denke ich, weil es den Dienst startet, also können Sie hinzufügen stopService(someIntent); unter dem Code.


22
2017-09-23 17:01



    public boolean checkServiceRunning(){
         ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
        for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) 
                {
                    if ("com.example.yourpackagename.YourServiceName"
                            .equals(service.service.getClassName())) 
                    {
                        return true;
                    }
                }
             return false;
    }

13
2017-07-14 03:23



Ich habe eine der oben dargestellten Lösungen etwas modifiziert, aber statt eines allgemeinen String-Namens die Klasse übergeben, um sicher zu sein, Strings zu vergleichen, die von derselben Methode kommen class.getName()

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

    public static boolean isServiceRunning(Context context,Class<?> serviceClass){
        final ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
        final List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);

        for (RunningServiceInfo runningServiceInfo : services) {
            Log.d(Constants.TAG, String.format("Service:%s", runningServiceInfo.service.getClassName()));
            if (runningServiceInfo.service.getClassName().equals(serviceClass.getName())){
                return true;
            }
        }
        return false;
    }
}

und dann

Boolean isServiceRunning = ServiceTools.isServiceRunning(
                    MainActivity.this.getApplicationContext(),
                    BackgroundIntentService.class);

11
2017-07-13 14:26



Ich möchte nur eine Notiz zu der Antwort von @Snicolas hinzufügen. Die folgenden Schritte können verwendet werden, um den Stopp-Dienst mit / ohne Anruf zu überprüfen onDestroy().

  1. onDestroy() aufgerufen: Gehe zu Einstellungen -> Anwendung -> Laufende Dienste -> Wähle und stoppe deinen Dienst.

  2. onDestroy() nicht aufgerufen: Gehen Sie zu Einstellungen -> Anwendung -> Anwendungen verwalten -> Wählen Sie "Erzwingen" und beenden Sie Ihre Anwendung, in der Ihr Dienst ausgeführt wird. Da Ihre Anwendung hier jedoch gestoppt wird, werden die Dienstinstanzen definitiv gestoppt.

Abschließend möchte ich erwähnen, dass der dort erwähnte Ansatz mit einer statischen Variable in Singleton-Klasse für mich funktioniert.


7
2017-09-16 16:54



onDestroy wird im Service nicht immer aufgerufen, das ist nutzlos!

Zum Beispiel: Führen Sie die App einfach erneut mit einer Änderung von Eclipse aus. Die Anwendung wird mit SIG: 9 gewaltsam beendet.


6
2018-02-12 04:26



Dies ist ein Auszug aus Android Dokumente

Bestellte Sendungen (gesendet mit Context.sendOrderedBroadcast) sind   an jeweils einen Empfänger geliefert. Wie jeder Empfänger ausführt   drehen, es kann ein Ergebnis an den nächsten Empfänger weitergeben, oder es kann   die Übertragung vollständig abbrechen, damit sie nicht an andere weitergegeben wird   Empfänger.

Stellen Sie sich diesen Hack als "Ping" vor Service Da wir synchron senden können, können wir ein Ergebnis synchron auf dem UI-Thread senden.

Service

BroadcastReceiver .

@Override
public void onCreate() {
   LocalBroadcastManager
     .getInstance(this)
     .registerReceiver(new ServiceEchoReceiver(), IntentFilter("echo");
}

private class ServiceEchoReceiver{
    public void onReceive (Context context, Intent intent) {
      LocalBroadcastManager
         .getInstance(this)
         .sendBroadcastSync(new Intent("echo"));
    }
}

Activity

    bool serviceRunning = false;

    protected void onCreate (Bundle savedInstanceState){
        LocalBroadcastManager.getInstance(this).registerReceiver(echo);
        LocalBroadcastManager.getInstance(this).sendBroadcastSync(new Intent("echo"));
        if(!serviceRunning){
           //try and run the service
        }
    }

    private BroadcastReceiver echo = new BroadcastReceiver(){
        public void onReceive (Context context, Intent intent) {
          serviceRunning = true;   
        }
    }

6
2017-09-19 17:48