segundo quitar plano permanentes para notificaciones mantener desactivar cerrar automaticamente app aplicaciones activar android android-service

quitar - ¿Cómo comprobar si un servicio se está ejecutando en Android?



mantener aplicaciones en segundo plano android (23)

La respuesta de geekQ pero en clase Kotlin. Gracias geek

fun isMyServiceRunning(serviceClass : Class<*> ) : Boolean{ var manager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager for (service in manager.getRunningServices(Integer.MAX_VALUE)) { if (serviceClass.name.equals(service.service.className)) { return true } } return false }

La llamada

isMyServiceRunning(NewService::class.java)

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

Quiero una actividad de Android que cambie el estado del servicio; me permite encenderlo si está apagado y apagarlo si está encendido.


¡Lo tengo!

DEBES llamar a startService() para que tu servicio se registre correctamente y no será suficiente pasar BIND_AUTO_CREATE .

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


A continuación se muestra un hack elegante que cubre todos los Ifs . Esto es solo para servicios locales.

public final class AService extends Service { private static AService mInstance = null; public static boolean isServiceCreated() { try { // If instance was not cleared but the service was destroyed an Exception will be thrown return mInstance != null && mInstance.ping(); } catch (NullPointerException e) { // destroyed/not-started return false; } } /** * Simply returns true. If the service is still active, this method will be accessible. * @return */ private boolean ping() { return true; } @Override public void onCreate() { mInstance = this; } @Override public void onDestroy() { mInstance = null; } }

Y luego más tarde:

if(AService.isServiceCreated()){ ... }else{ startService(...); }


Dentro de TheServiceClass define:

public static Boolean serviceRunning = false;

Entonces en onStartCommand (...)

public int onStartCommand(Intent intent, int flags, int startId) { serviceRunning = true; ... } @Override public void onDestroy() { serviceRunning = false; }

Luego, llame a if(TheServiceClass.serviceRunning == true) de cualquier clase.


En primer lugar, no debe intentar acceder al servicio utilizando el ActivityManager. (Discutido here )

Los servicios pueden ejecutarse por su cuenta, vinculados a una actividad o a ambas. La forma de verificar una Actividad si su Servicio se está ejecutando o no es haciendo una interfaz (que extienda el Binder) donde declara los métodos que tanto la Actividad como el Servicio comprenden. Puede hacer esto creando su propia interfaz donde declare, por ejemplo, "isServiceRunning ()". Luego, puede vincular su Actividad a su Servicio, ejecutar el método isServiceRunning (), el Servicio comprobará si está funcionando o no y devuelve un booleano a su Actividad.

También puede usar este método para detener su Servicio o interactuar con él de otra manera.

Utilicé este tutorial para aprender a implementar este escenario en mi aplicación.


Este es un extracto de documentos de Android :

Como sendBroadcast(Intent) , pero si hay algún receptor para la Intención, esta función los bloqueará y los enviará inmediatamente antes de regresar.

Piense en este truco como "hacer ping" al Service ya que podemos transmitir de forma sincronizada, podemos transmitir y obtener un resultado, sincrónicamente, en el subproceso de la interfaz de usuario.

Service

@Override public void onCreate() { LocalBroadcastManager .getInstance(this) .registerReceiver(new ServiceEchoReceiver(), IntentFilter("ping"); } private class ServiceEchoReceiver{ 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){ //try and run the service } } private BroadcastReceiver pong = new BroadcastReceiver(){ public void onReceive (Context context, Intent intent) { serviceRunning = true; } }


Esto se aplica más a la depuración de Intent Service, ya que genera un hilo, pero también puede funcionar para servicios regulares. Encontré este hilo gracias a Binging.

En mi caso, jugué un poco con el depurador y encontré la vista de hilos. Se parece al ícono de la viñeta en MS Word. De todos modos, no tienes que estar en modo depurador para usarlo. Haga clic en el proceso y haga clic en ese botón. Los Servicios de Intención se mostrarán mientras se ejecutan, al menos en el emulador.


He modificado ligeramente una de las soluciones presentadas anteriormente, pero al pasar la clase en lugar de un nombre de cadena genérico, para estar seguro de comparar las 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);


La forma correcta de verificar si un servicio se está ejecutando es simplemente preguntarlo. Implemente un BroadcastReceiver en su servicio que responda a pings de sus actividades. Registre el BroadcastReceiver cuando se inicie el servicio y anule el registro cuando se destruya el servicio. Desde su actividad (o cualquier componente), envíe un intento de transmisión local al servicio y, si responde, sabe que se está ejecutando. Note la sutil diferencia entre ACTION_PING y ACTION_PONG en el siguiente código.

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


Nuevamente, otra alternativa que las personas podrían encontrar más limpia si usan intentos pendientes (por ejemplo, con el AlarmManager :

public static boolean isRunning(Class<? extends Service> serviceClass) { final Intent intent = new Intent(context, serviceClass); return (PendingIntent.getService(context, CODE, intent, PendingIntent.FLAG_NO_CREATE) != null); }

Donde CODE es una constante que define de forma privada en su clase para identificar los intentos pendientes asociados a su servicio.


Para el caso de uso aquí indicado, simplemente podemos utilizar el valor de retorno del método stopService() . Devuelve true si existe el servicio especificado y se cancela. En caso contrario devuelve false . Por lo tanto, puede reiniciar el servicio si el resultado es false contrario se garantiza que el servicio actual se ha detenido. :) Sería mejor si miras this .


Puede haber varios servicios con el mismo nombre de clase.

Acabo de crear dos aplicaciones. El nombre del paquete de la primera aplicación es com.example.mock . Creé un subpaquete llamado lorem en la aplicación y un servicio llamado Mock2Service . Por lo tanto, su nombre com.example.mock.lorem.Mock2Service es com.example.mock.lorem.Mock2Service .

Luego creé la segunda aplicación y un servicio llamado Mock2Service . El nombre del paquete de la segunda aplicación es com.example.mock.lorem . El nombre completo del servicio también es com.example.mock.lorem.Mock2Service .

Aquí está mi salida logcat.

03-27 12:02:19.985: D/TAG(32155): Mock-01: com.example.mock.lorem.Mock2Service 03-27 12:02:33.755: D/TAG(32277): Mock-02: com.example.mock.lorem.Mock2Service

Una mejor idea es comparar las instancias de ComponentName porque equals() de ComponentName compara los nombres de los paquetes y los nombres de las clases. Y no puede haber dos aplicaciones con el mismo nombre de paquete instalado en un dispositivo.

El método equals () de ComponentName .

@Override public boolean equals(Object obj) { try { if (obj != null) { ComponentName other = (ComponentName)obj; // Note: no null checks, because mPackage and mClass can // never be null. return mPackage.equals(other.mPackage) && mClass.equals(other.mClass); } } catch (ClassCastException e) { } return false; }

ComponentName


Puedes usar esto (no lo intenté 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 Intent) .

Creo que esto no es como verificar, porque está iniciando el servicio, por lo que puede agregar stopService(someIntent); bajo el codigo


Si el servicio pertenece a otro proceso o APK, use la solución basada en el ActivityManager.

Si tiene acceso a su fuente, solo use la solución basada en un campo estático. Pero en lugar de eso, usar un booleano sugeriría usar un objeto Date. Mientras el servicio se está ejecutando, simplemente actualice su valor a ''ahora'' y cuando termine, configúrelo en nulo. Desde la actividad puede verificar si es nulo o la fecha es demasiado antigua, lo que significará que no se está ejecutando.

También puede enviar notificaciones de transmisión desde su servicio indicando que se está ejecutando junto con información adicional como el progreso.


Solo quiero añadir una nota a la respuesta por @Snicolas. Los siguientes pasos pueden usarse para verificar el servicio de parada con / sin llamar a 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 -> Seleccione y "Forzar detención" su aplicación en la que se ejecuta su servicio. Sin embargo, como su aplicación se detiene aquí, definitivamente las instancias de 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 está funcionando para mí.


Tómalo con calma chicos ... :)

Creo que la solución más adecuada es mantener un par clave-valor en SharedPreferences sobre si el servicio se está ejecutando o no.

La lógica es muy recta; en cualquier posición deseada en su clase de servicio; ponga un valor booleano que actuará como un indicador para usted sobre si el servicio se está ejecutando o no. Luego lee este valor donde quieras en tu aplicación.

A continuación se muestra un código de muestra que estoy usando en mi aplicación:

En mi clase de servicio (un servicio para transmisión de audio), ejecuto el siguiente código cuando el servicio está activo;

private void updatePlayerStatus(boolean isRadioPlaying) { SharedPreferences sharedPref = this.getSharedPreferences(getString(R.string.str_shared_file_name), Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPref.edit(); editor.putBoolean(getString(R.string.str_shared_file_radio_status_key), isRadioPlaying); editor.commit(); }

Luego, en cualquier actividad de mi aplicación, estoy revisando el estado del servicio con la ayuda de seguir el código;

private boolean isRadioRunning() { SharedPreferences sharedPref = this.getSharedPreferences(getString(R.string.str_shared_file_name), Context.MODE_PRIVATE); return sharedPref.getBoolean(getString(R.string.str_shared_file_radio_status_key), false); }

Sin permisos especiales, sin bucles ... De manera fácil, solución limpia :)

Si necesita información adicional, por favor consulte el link

Espero que esto ayude.


Tuve el mismo problema no hace mucho. Como mi servicio era local, terminé simplemente usando un campo estático en la clase de servicio para cambiar el estado, como se describe here por hackbod

EDITAR (para el registro):

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

Si su código de cliente y servidor es parte del mismo .apk y está enlazando al servicio con una Intención concreta (una que especifica la clase de servicio exacta), simplemente puede hacer que su servicio establezca una variable global cuando se ejecute. su cliente puede verificar

No tenemos una API deliberadamente para verificar si un servicio se está ejecutando porque, casi sin fallar, cuando quieres hacer algo así, terminas con condiciones de carrera en tu código.


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 pueda ser detectado por el servicio no es una buena idea, ya que iniciará el servicio si no se está ejecutando.

Entonces, como sugirió miracle2k, 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 claro, sugiero transformar el servicio en un singleton con una búsqueda muy perezosa: es decir, no hay instanciación en absoluto de la instancia de singleton 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 propio singleton. El servicio solo se inicia a través de los métodos normales de inicio del servicio.

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

El código se verá como:

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 está fuera de la aplicación / paquete del servicio. Si sus clases están fuera del servicio / paquete de servicio, puede consultar el ActivityManager con las limitaciones subrayadas por Pieter-Jan Van Robays.


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 los servicios en ejecución provistos por el sistema operativo Android a través de ActivityManager#getRunningServices .

Todos los enfoques que utilicen 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 finalizar el proceso o a cuál de las llamadas devueltas se llama o no. Tenga en cuenta la columna "killable" en la tabla de eventos del ciclo de vida en la documentación de Android.


Versión Xamarin C #:

private bool isMyServiceRunning(System.Type cls) { ActivityManager manager = (ActivityManager)GetSystemService(Context.ActivityService); foreach (var service in manager.GetRunningServices(int.MaxValue)) { if (service.Service.ClassName.Equals(Java.Lang.Class.FromType(cls).CanonicalName)) { return true; } } return false; }


onDestroy no siempre se llama en el servicio, por lo que es inútil!

Por ejemplo: simplemente ejecute la aplicación nuevamente con un cambio desde Eclipse. La aplicación se cierra a la fuerza usando SIG: 9.


simple uso enlazar con no crear auto - ver ps. y actualizar ...

public abstract class Context { ... /* * @return {true} If you have successfully bound to the service, * {false} is returned if the connection is not made * so you will not receive the service object. */ public abstract boolean bindService(@RequiresPermission Intent service, @NonNull ServiceConnection conn, @BindServiceFlags int flags);

ejemplo:

Intent bindIntent = new Intent(context, Class<Service>); boolean bindResult = context.bindService(bindIntent, ServiceConnection, 0);

¿Por qué no usar? getRunningServices ()

List<ActivityManager.RunningServiceInfo> getRunningServices (int maxNum) Return a list of the services that are currently running.

Nota: este método solo está destinado a la depuración o la implementación de interfaces de usuario de tipo de gestión de servicios.

PD. La documentación de Android es engañosa. He abierto un problema en el rastreador de google para eliminar cualquier duda:

https://issuetracker.google.com/issues/68908332

Como podemos ver, el servicio de vinculación en realidad invoca una transacción a través del vinculador ActivityManager a través de los enlazadores de caché de servicio. No doy seguimiento del servicio responsable de la vinculación, pero como podemos ver, el resultado de la vinculación es:

int res = ActivityManagerNative.getDefault().bindService(...); return res != 0;

La transacción se realiza a través de la carpeta:

ServiceManager.getService("activity");

siguiente:

public static IBinder getService(String name) { try { IBinder service = sCache.get(name); if (service != null) { return service; } else { return getIServiceManager().getService(name);

esto se establece en ActivityThread a través de:

public final void bindApplication(...) { if (services != null) { // Setup the service cache in the ServiceManager ServiceManager.initServiceCache(services); }

Esto se llama en ActivityManagerService en el método:

private final boolean attachApplicationLocked(IApplicationThread thread, int pid) { ... thread.bindApplication(... , getCommonServicesLocked(),...)

entonces:

private HashMap<String, IBinder> getCommonServicesLocked() {

pero no hay "actividad" solo paquete de ventana y alarma ..

por lo que necesitamos volver a llamar:

return getIServiceManager().getService(name); sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());

esto hace llamar a través de:

mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);

lo que lleva a :

BinderInternal.getContextObject()

y este es el método nativo ....

/** * Return the global "context object" of the system. This is usually * an implementation of IServiceManager, which you can use to find * other services. */ public static final native IBinder getContextObject();

Ahora no tengo tiempo para excavar en c, así que hasta que diseccione la llamada de reposo suspendo mi respuesta.

pero la mejor manera de verificar si el servicio se está ejecutando es crear un enlace (si no se crea un enlace, el servicio no existe), y consultar al servicio sobre su estado a través del enlace (utilizando el indicador interno almacenado en su estado).

actualización 23.06.2018

me parecieron interesantes

/** * Provide a binder to an already-bound service. This method is synchronous * and will not start the target service if it is not present, so it is safe * to call from {@link #onReceive}. * * For peekService() to return a non null {@link android.os.IBinder} interface * the service must have published it before. In other words some component * must have called {@link android.content.Context#bindService(Intent, ServiceConnection, int)} on it. * * @param myContext The Context that had been passed to {@link #onReceive(Context, Intent)} * @param service Identifies the already-bound service you wish to use. See * {@link android.content.Context#bindService(Intent, ServiceConnection, int)} * for more information. */ public IBinder peekService(Context myContext, Intent service) { IActivityManager am = ActivityManager.getService(); IBinder binder = null; try { service.prepareToLeaveProcess(myContext); binder = am.peekService(service, service.resolveTypeIfNeeded( myContext.getContentResolver()), myContext.getOpPackageName()); } catch (RemoteException e) { } return binder; }

en breve :)

"Proporcionar una carpeta a un servicio ya enlazado. Este método es síncrono y no iniciará el servicio de destino si no está presente".

el servicio público peekService de IBinder (servicio intencional, tipo de cadena resuelto, paquete de llamada de cadena) lanza RemoteException;

*

public static IBinder peekService(IBinder remote, Intent service, String resolvedType) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken("android.app.IActivityManager"); service.writeToParcel(data, 0); data.writeString(resolvedType); remote.transact(android.os.IBinder.FIRST_CALL_TRANSACTION+84, data, reply, 0); reply.readException(); IBinder binder = reply.readStrongBinder(); reply.recycle(); data.recycle(); return binder; }

*


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