¿Cómo verifico si se está ejecutando un servicio en segundo plano?
Quiero una actividad de Android que alterne el estado del servicio; me permite activarla si está desactivada y desactivada si está activada.
android
android-service
abeja
fuente
fuente
getRunningTasks()
, probablemente lo será.Respuestas:
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 alternar el estado, como lo describe hackbod aquí
EDITAR (para el registro):
Aquí está la solución propuesta por hackbod:
fuente
onDestroy()
no se llama al servicio. Por lo tanto, la variable estática no se puede actualizar en tal escenario, lo que resulta en un comportamiento inconsistente.Uso lo siguiente desde dentro de una actividad:
Y lo llamo usando:
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 onDestroy o onSometing events 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 se llaman o no. Tenga en cuenta la columna "eliminable" en la tabla de eventos del ciclo de vida en la documentación de Android.
fuente
getRunningServices
está en desuso. Esta respuesta necesita una actualización para la versión más nueva.¡Entendido!
Usted DEBE llamar
startService()
a su servicio para estar debidamente registrado y el pasoBIND_AUTO_CREATE
no será suficiente.Y ahora la clase ServiceTools:
fuente
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 puede ser atrapado por el servicio no es una buena idea, ya que comenzará 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 limpio, sugiero transformar el servicio en un singleton con una recuperación muy perezosa: es decir, no hay instanciación de la instancia de singleton 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í. 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 singleton para cambiar el nombre del método getInstance confuso en algo como el
isInstanceCreated() : boolean
método.El código se verá así:
Esta solución es elegante, pero solo es relevante si tiene acceso a la clase de servicio y solo para clases dentro de la aplicación / paquete del servicio. Si sus clases están fuera de la aplicación / paquete de servicio, puede consultar el ActivityManager con las limitaciones subrayadas por Pieter-Jan Van Robays.
fuente
Puede usar esto (aún no lo intenté, pero espero que esto funcione):
El método startService devuelve un objeto ComponentName si ya hay un servicio en ejecución. Si no, se devolverá nulo.
Vea el resumen público ComponentName startService (servicio de intención) .
Esto no es como verificar, creo, porque está iniciando el servicio, por lo que puede agregar
stopService(someIntent);
bajo el código.fuente
if(startService(someIntent) != null)
eso lo comprobará,IsserviceRunning
pero también jugará un nuevo servicio.fuente
Un extracto de documentos de Android :
Piense en este truco como "ping" al
Service
. Como podemos transmitir sincrónicamente, podemos transmitir y obtener un resultado sincrónicamente , en el hilo de la interfaz de usuario.Service
Activity
El ganador en muchas aplicaciones es, por supuesto, un campo booleano estático en el servicio que está configurado en
true
inService.onCreate()
y tofalse
inService.onDestroy()
porque es mucho más simple.fuente
Modifiqué ligeramente una de las soluciones presentadas anteriormente, pero pasé la clase en lugar de un nombre de cadena genérico, para asegurarme de comparar las cadenas que salen del mismo método
class.getName()
y entonces
fuente
Class<? extends Service>
La forma correcta de verificar si un servicio se está ejecutando es simplemente preguntarlo. Implemente un BroadcastReceiver en su servicio que responda a los 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 una intención de transmisión local al servicio y si responde, sabe que se está ejecutando. Tenga en cuenta la sutil diferencia entre ACTION_PING y ACTION_PONG en el siguiente código.
fuente
Solo quiero agregar una nota a la respuesta de @Snicolas. Los siguientes pasos se pueden utilizar para verificar detener el servicio con / sin llamadas
onDestroy()
.onDestroy()
llamado: Vaya a Configuración -> Aplicación -> Servicios en ejecución -> Seleccione y detenga su servicio.onDestroy()
no llamado: vaya a Configuración -> Aplicación -> Administrar aplicaciones -> Seleccione y "Forzar detención" de su aplicación en la que se está ejecutando su servicio. Sin embargo, como su aplicación se detiene aquí, definitivamente también se detendrán las instancias de servicio.Finalmente, me gustaría mencionar que el enfoque mencionado allí usando una variable estática en la clase singleton está funcionando para mí.
fuente
onDestroy
no siempre se llama en el servicio, ¡así que esto es inútil!Por ejemplo: simplemente ejecute la aplicación nuevamente con un cambio desde Eclipse. La aplicación se cierra a la fuerza con SIG: 9.
fuente
En primer lugar, no debe intentar acceder al servicio utilizando el ActivityManager. (Discutido aquí )
Los servicios pueden ejecutarse por sí mismos, estar vinculados a una Actividad o ambas. La forma de registrar una Actividad si su Servicio se está ejecutando o no es haciendo una interfaz (que extienda Binder) donde declare métodos que tanto la Actividad como el Servicio entiendan. Puede hacer esto haciendo su propia interfaz donde declara, por ejemplo, "isServiceRunning ()". Luego puede vincular su Actividad a su Servicio, ejecutar el método isServiceRunning (), el Servicio verificará por sí mismo si se está ejecutando o no y devolverá un valor 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 cómo implementar este escenario en mi aplicación.
fuente
Una vez más, otra alternativa que las personas podrían encontrar más limpia si usan intenciones pendientes (por ejemplo, con
AlarmManager
:Donde
CODE
es una constante que usted define de forma privada en su clase para identificar los intentos pendientes asociados a su servicio.fuente
A continuación se muestra un elegante truco que cubre todo
Ifs
. Esto es solo para servicios locales.Y luego más tarde:
fuente
Versión de Xamarin C #:
fuente
GetSystemService
.Para el caso de uso dado aquí, simplemente podemos hacer uso del
stopService()
valor de retorno del método. Regresatrue
si existe el servicio especificado y se elimina. De lo contrario, vuelvefalse
. Por lo tanto, puede reiniciar el servicio si, de lofalse
contrario, se garantiza que el servicio actual se ha detenido. :) Sería mejor si echas un vistazo a esto .fuente
Otro enfoque usando kotlin. Inspirado en las respuestas de otros usuarios
Como extensión de kotlin
Uso
fuente
En kotlin puede agregar una variable booleana en un objeto complementario y verificar su valor de cualquier clase que desee:
Cambie su valor cuando se crea y destruye el servicio
fuente
En su subclase de servicio, utilice un booleano estático para obtener el estado del servicio como se muestra a continuación.
MyService.kt
MainActivity.kt
fuente
Para kotlin, puede usar el siguiente código.
fuente
La llamada
fuente
ActivityManager.getRunningServices
está en desuso desde Android OPuede 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 llamadolorem
en la aplicación y un servicio llamadoMock2Service
. Entonces su nombre completo escom.example.mock.lorem.Mock2Service
.Luego creé la segunda aplicación y un servicio llamado
Mock2Service
. El nombre del paquete de la segunda aplicación escom.example.mock.lorem
. El nombre completo del servicio escom.example.mock.lorem.Mock2Service
.Aquí está mi salida de logcat.
Una mejor idea es comparar
ComponentName
instancias debidoequals()
aComponentName
compara ambos nombres de paquetes y nombres de clase. Y no puede haber dos aplicaciones con el mismo nombre de paquete instalado en un dispositivo.El método equals () de
ComponentName
.Nombre del componente
fuente
Por favor use este código.
fuente
Esto se aplica más a la depuración de Intent Service ya que generan un hilo, pero también puede funcionar para servicios regulares. Encontré este hilo gracias a Binging
En mi caso, jugué con el depurador y encontré la vista de hilo. Se parece al icono de viñeta en MS Word. De todos modos, no tiene que estar en modo depurador para usarlo. Haga clic en el proceso y haga clic en ese botón. Cualquier Intent Services aparecerá mientras se está ejecutando, al menos en el emulador.
fuente
Si el servicio pertenece a otro proceso o APK, use la solución basada en el ActivityManager.
Si tiene acceso a su fuente, simplemente use la solución basada en un campo estático. Pero en lugar de 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 como nulo. Desde la actividad puede verificar si es nula o si la fecha es demasiado antigua, lo que significa que no se está ejecutando.
También puede enviar notificaciones de difusión desde su servicio indicando que se está ejecutando junto con más información como progreso.
fuente
Dentro de TheServiceClass define:
Luego en onStartCommand (...)
Luego, llame
if(TheServiceClass.serviceRunning == true)
desde cualquier clase.fuente
stopService
. Al menos para servicios de intención.onDestroy()
será llamado de inmediato, peroonHandleIntent()
seguirá ejecutándoseenlace de uso simple con no crear automáticamente- ver ps. y actualizar ...ejemplo:
¿Por qué no usar? getRunningServices ()
Nota: este método solo está destinado a depurar o implementar 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 enlace en realidad invoca una transacción a través del enlazador ActivityManager a través de los enlazadores de caché del servicio: no sé qué servicio es responsable del enlace, pero como podemos ver, el resultado para el enlace es:
La transacción se realiza a través de la carpeta:
siguiente:
Esto se establece en ActivityThread a través de:
Esto se llama en ActivityManagerService en el método:
entonces:
pero no hay "actividad" solo paquete de ventanas y alarma.
entonces necesitamos volver a llamar:
esto hace llamar a través de:
lo que lleva a :
y este es un método nativo ...
No tengo tiempo ahora para cavar en C, así que hasta que diseccione la llamada de descanso, suspenderé mi respuesta.
pero la mejor manera de verificar si el servicio se está ejecutando es crear un enlace (si el enlace no se crea, el servicio no existe) y consultar al servicio sobre su estado a través del enlace (usando el indicador interno almacenado en este estado).
actualizar 23.06.2018
los encontré interesantes:
en breve :)
"Proporcione una carpeta a un servicio ya vinculado. Este método es sincrónico y no iniciará el servicio de destino si no está presente".
public pederService de IBinder (servicio de intención, String resolveType, String callingPackage) produce RemoteException;
fuente
Mi conversión de Kotlin de las
ActivityManager::getRunningServices
respuestas basadas. Pon esta función en una actividadfuente
Es posible que use estas opciones de las opciones de Desarrollador de Android para ver si su servicio aún se está ejecutando en segundo plano.
fuente
Tómelo con calma chicos ... :)
Creo que la solución más adecuada es mantener un par clave-valor
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; pon un valor booleano que actuará como un indicador para ti sobre si el servicio se está ejecutando o no. Luego lea este valor cuando lo desee en su 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 Audio Stream), ejecuto el siguiente código cuando el servicio está activo;
Luego, en cualquier actividad de mi aplicación, verifico el estado del servicio con la ayuda del siguiente código;
Sin permisos especiales, sin bucles ... Manera fácil, solución limpia :)
Si necesita información adicional, consulte el enlace
Espero que esto ayude.
fuente
onDestroy
no siempre se llama cuando se cancela el servicio. Por ejemplo, he visto mis servicios eliminados en situaciones de poca memoria sinonDestroy
ser llamado.