Pregunta ¿Cómo verificar si un servicio se está ejecutando en Android?


¿Cómo puedo verificar si se está ejecutando un servicio en segundo plano (en Android)?

Quiero una actividad de Android que conmute el estado del servicio; me permite activarlo si está apagado y apagado si está activado.


794
2018-03-01 18:09


origen


Respuestas:


Tuve el mismo problema no hace mucho tiempo. Como mi servicio era local, terminé simplemente usando un campo estático en la clase de servicio para alternar el estado, como lo describe hackbod aquí

EDITAR (para el registro):

Aquí está la solución propuesta por hackbod:

Si su código de cliente y servidor es parte de la misma .apk y está   vinculante para el servicio con una intención concreta (una que especifica el   clase de servicio exacta), entonces simplemente puede hacer que su servicio establezca un   variable global cuando se está ejecutando que su cliente puede verificar.

Deliberadamente no tenemos una API para verificar si un servicio es   corriendo porque, casi sin falta, cuando quieres hacer algo   así terminas con condiciones de carrera en tu código.


248
2018-03-03 22:58



Uso lo siguiente desde dentro de una actividad:

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

Y lo llamo usando:

isMyServiceRunning(MyService.class)

Esto funciona de manera confiable, ya que se basa en la información sobre la ejecución de servicios proporcionados por el sistema operativo Android a través de ActivityManager # getRunningServices.

Todos los enfoques que usan eventos onDestroy o onSometing o Binders o variables estáticas no funcionarán de manera confiable porque como desarrollador nunca se sabe, cuando Android decide matar su proceso o cuáles de las devoluciones de llamada mencionadas son llamadas o no. Tenga en cuenta la columna "Killable" en el tabla de eventos de ciclo de vida en la documentación de Android.


1518
2018-05-07 12:54



¡Lo tengo!

DEBE llamada startService() para que su servicio esté debidamente registrado y aprobado BIND_AUTO_CREATE no será suficiente

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

Y ahora la clase 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;
     }
}

67
2018-02-12 04:42



Un pequeño complemento es:

Mi objetivo es saber si un servicio se está ejecutando sin ejecutarlo realmente si no se está ejecutando.

Llamar a bindService o llamar a un intento que el servicio puede capturar no es una buena idea, ya que iniciará el servicio si no se está ejecutando.

Por lo tanto, como miracle2k sugirió, lo mejor es tener un campo estático en la clase de servicio para saber si el servicio se ha iniciado o no.

Para hacerlo aún más limpio, sugiero transformar el servicio en un singleton con una búsqueda muy vaga: es decir, no hay instanciación en absoluto de la semifallo instancia a través de métodos estáticos. El método estático getInstance de su servicio / singleton solo devuelve la instancia del singleton si se ha creado. Pero en realidad no inicia ni instancia el singleton en sí mismo. El servicio solo se inicia a través de los métodos normales de inicio del servicio.

Sería aún más limpio modificar el patrón de diseño singleton para cambiar el nombre del confuso método getInstance en algo así como isInstanceCreated() : boolean método.

El código se verá así:

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

Esta solución es elegante, pero solo es relevante si tiene acceso a la clase de servicio y solo para las clases en la aplicación / paquete del servicio. Si sus clases están fuera de la aplicación / paquete de servicio, puede consultar el ActivityManager con limitaciones subrayadas por Pieter-Jan Van Robays.


51
2018-05-20 10:58



Puede usar esto (no intenté esto todavía, pero espero que esto funcione):

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

El método startService devuelve un objeto ComponentName si ya hay un servicio en ejecución. Si no, se devolverá nulo.

Ver Resumen público ComponentName startService (Servicio de atención).

Esto no es como verificar, creo, porque está comenzando el servicio, por lo que puedes agregar stopService(someIntent); bajo el código


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



He modificado ligeramente una de las soluciones presentadas anteriormente, pero pasando la clase en lugar de un nombre de cadena genérico, para estar seguro de comparar cadenas que salen del mismo método 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;
    }
}

y entonces

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

11
2017-07-13 14:26



Solo quiero agregar una nota a la respuesta de @Snicolas. Los siguientes pasos se pueden usar para verificar el servicio de parada con / sin llamada onDestroy().

  1. onDestroy() llamado: vaya a Configuración -> Aplicación -> Servicios en ejecución -> Seleccione y detenga su servicio.

  2. onDestroy() no llamado: vaya a Configuración -> Aplicación -> Administrar aplicaciones -> Seleccionar y "Forzar detención" de su aplicación en la cual se está ejecutando su servicio. Sin embargo, como su aplicación se detiene aquí, definitivamente las instancias del servicio también se detendrán.

Finalmente, me gustaría mencionar que el enfoque mencionado allí usando una variable estática en la clase de singleton me funciona.


7
2017-09-16 16:54