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.

29voto

J.R Punkte 2035
/**
 * Check if the service is Running 
 * @param serviceClass the class of the Service
 *
 * @return true if the service is running otherwise false
 */
public boolean checkServiceRunning(Class<?> serviceClass){
    ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE))
    {
        if (serviceClass.getName().equals(service.service.getClassName()))
        {
            return true;
        }
    }
    return false;
}

28voto

Peter Chaula Punkte 3074

Ein Auszug aus Android docs:

Wie sendBroadcast(Intent) aber wenn es Empfänger gibt für Intent gibt, wird diese Funktion blockieren und sie sofort versenden. bevor sie zurückkehrt.

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

Service

@Override
public void onCreate() {
   LocalBroadcastManager
     .getInstance(this)
     .registerReceiver(new ServiceEchoReceiver(), new IntentFilter("ping"));
     //do not forget to deregister the receiver when the service is destroyed to avoid
     //any potential memory leaks 
}

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

Activity

    bool serviceRunning = false;

    protected void onCreate (Bundle savedInstanceState){
        LocalBroadcastManager.getInstance(this).registerReceiver(pong, new IntentFilter("pong"));
        LocalBroadcastManager.getInstance(this).sendBroadcastSync(new Intent("ping"));
        if(!serviceRunning){
           //run the service
        }
    }

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

Der Gewinner in vielen Anwendungen ist natürlich ein statisches boolesches Feld des Dienstes, das auf true en Service.onCreate() und an false en Service.onDestroy() weil es viel einfacher ist.

0 Stimmen

Dies ist eine viel bessere Lösung als die akzeptierte, die fehlschlägt, wenn Android den Dienst beendet, da die globale Variablenmethode immer noch anzeigen würde, dass der Dienst läuft, obwohl er es in Wirklichkeit nicht mehr tut. Dieser synchrone Ping-Pong-Broadcast-Trick ist tatsächlich die EINZIGE verlässliche Methode, um zu prüfen, ob ein Dienst noch aktiv ist. Nur so können Sie den Dienst einfach fragen, ob er vorhanden ist. Wenn er antwortet, ist der Dienst aktiv und läuft, wenn nicht, wurde er entweder nicht gestartet oder heruntergefahren, entweder programmatisch oder vom System, um Speicherplatz zu gewinnen.

1 Stimmen

18voto

Ein anderer Ansatz mit Kotlin. Inspiriert durch die Antworten anderer Benutzer

fun isMyServiceRunning(serviceClass: Class<*>): Boolean {
    val manager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    return manager.getRunningServices(Integer.MAX_VALUE)
            .any { it.service.className == serviceClass.name }
}

Als Kotlin-Erweiterung

fun Context.isMyServiceRunning(serviceClass: Class<*>): Boolean {
    val manager = this.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    return manager.getRunningServices(Integer.MAX_VALUE)
            .any { it.service.className == serviceClass.name }
}

Verwendung

context.isMyServiceRunning(MyService::class.java)

3 Stimmen

HINWEIS: getRunningServices ist jetzt veraltet, aber es scheint, dass die Methode nicht gelöscht werden wird.

15voto

Ben H Punkte 3757

Der richtige Weg, um zu prüfen, ob ein Dienst läuft, ist, ihn einfach zu fragen. Implementieren Sie einen BroadcastReceiver in Ihrem Dienst, der auf Pings von Ihren Aktivitäten antwortet. Registrieren Sie den BroadcastReceiver, wenn der Dienst startet, und heben Sie die Registrierung auf, wenn der Dienst zerstört wird. Von Ihrer Aktivität (oder einer beliebigen Komponente), senden Sie eine lokale Übertragung und wenn er antwortet, wissen Sie, dass er läuft. Beachten Sie den feinen Unterschied zwischen ACTION_PING und ACTION_PONG im folgenden Code.

public class PingableService extends Service {
    public static final String ACTION_PING = PingableService.class.getName() + ".PING";
    public static final String ACTION_PONG = PingableService.class.getName() + ".PONG";

    public int onStartCommand (Intent intent, int flags, int startId) {
        LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, new IntentFilter(ACTION_PING));
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy () {
        LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
        super.onDestroy();
    }

    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive (Context context, Intent intent) {
            if (intent.getAction().equals(ACTION_PING)) {
                LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getApplicationContext());
                manager.sendBroadcast(new Intent(ACTION_PONG));
            }
        }
    };
}

public class MyActivity extends Activity {
    private boolean isSvcRunning = false;

    @Override
    protected void onStart() {
        LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getApplicationContext());
        manager.registerReceiver(mReceiver, new IntentFilter(PingableService.ACTION_PONG));
        // the service will respond to this broadcast only if it's running
        manager.sendBroadcast(new Intent(PingableService.ACTION_PING));
        super.onStart();
    }

    @Override
    protected void onStop() {
        LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
        super.onStop();
    }

    protected BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive (Context context, Intent intent) {
            // here you receive the response from the service
            if (intent.getAction().equals(PingableService.ACTION_PONG)) {
                isSvcRunning = true;
            }
        }
    };
}

2 Stimmen

Dieser Ansatz gefällt mir eigentlich. Es ist ein wenig schwer Code weise aber wird immer funktionieren. Ich sehe nicht, dass Broadcast-Intents in absehbarer Zeit veraltet sein werden :)

0 Stimmen

Berücksichtigen Sie, dass eine Sendung verpasst werden kann.

1 Stimmen

Und ... LocalBroadcastManager ist jetzt veraltet ... (Randnotiz). Es ist aber trotzdem eine gute Lösung.

14voto

loretoparisi Punkte 14321

Ich habe eine der oben vorgestellten Lösungen geringfügig geändert, indem ich die Klasse anstelle eines generischen Zeichenkettennamens übergeben habe, um sicher zu sein, dass die Zeichenketten, die aus der gleichen Methode kommen, verglichen werden 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);

0 Stimmen

Um strenger zu sein, können Sie die Klasse param in Class<? extends Service>

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