Comment vérifier si un service d'arrière-plan est en cours d'exécution?
Je veux une activité Android qui permute l'état du service - cela me permet de l'activer s'il est désactivé et de le désactiver s'il est activé.
android
android-service
abeille
la source
la source
getRunningTasks()
, ce sera probablement le cas.Réponses:
J'ai eu le même problème il n'y a pas longtemps. Étant donné que mon service était local, j'ai fini par utiliser simplement un champ statique dans la classe de service pour basculer l'état, comme décrit par hackbod ici
EDIT (pour mémoire):
Voici la solution proposée par hackbod:
la source
onDestroy()
n'est pas appelé. La variable statique ne peut donc pas être mise à jour dans un tel scénario entraînant un comportement incohérent.J'utilise les éléments suivants à l'intérieur d'une activité:
Et je l'appelle en utilisant:
Cela fonctionne de manière fiable, car il est basé sur les informations sur l'exécution des services fournis par le système d'exploitation Android via ActivityManager # getRunningServices .
Toutes les approches utilisant des événements onDestroy ou onSometing ou des classeurs ou des variables statiques ne fonctionneront pas de manière fiable, car en tant que développeur, vous ne savez jamais, quand Android décide de tuer votre processus ou quels rappels mentionnés sont appelés ou non. Veuillez noter la colonne "killable" dans le tableau des événements du cycle de vie dans la documentation Android.
la source
getRunningServices
est dépréciée. Cette réponse nécessite une mise à jour pour une version plus récente.Je l'ai!
Vous DEVEZ appeler
startService()
pour que votre service soit correctement enregistré et le passageBIND_AUTO_CREATE
ne suffira pas.Et maintenant la classe ServiceTools:
la source
Un petit complément est:
Mon objectif est de savoir si un service est en cours d'exécution sans l'exécuter réellement s'il ne fonctionne pas.
Appeler bindService ou appeler une intention qui peut être interceptée par le service n'est pas une bonne idée, car il démarrera le service s'il n'est pas en cours d'exécution.
Ainsi, comme l'a suggéré miracle2k, le mieux est d'avoir un champ statique dans la classe de service pour savoir si le service a été démarré ou non.
Pour le rendre encore plus propre, je suggère de transformer le service en un singleton avec une extraction très très paresseuse: c'est-à-dire qu'il n'y a aucune instanciation du tout de l' instance de singleton par des méthodes statiques. La méthode statique getInstance de votre service / singleton renvoie simplement l'instance du singleton s'il a été créé. Mais il ne démarre ni n'instancie réellement le singleton lui-même. Le service est démarré uniquement via les méthodes normales de démarrage du service.
Il serait alors encore plus propre de modifier le modèle de conception singleton pour renommer la méthode getInstance déroutante en quelque chose comme la
isInstanceCreated() : boolean
méthode.Le code ressemblera à:
Cette solution est élégante, mais elle n'est pertinente que si vous avez accès à la classe de service et uniquement pour les classes à côté de l'application / package du service. Si vos classes sont en dehors de l'application / package de service, vous pouvez interroger le ActivityManager avec des limitations soulignées par Pieter-Jan Van Robays.
la source
Vous pouvez l'utiliser (je n'ai pas encore essayé, mais j'espère que cela fonctionne):
La méthode startService renvoie un objet ComponentName s'il existe un service déjà en cours d'exécution. Sinon, null sera retourné.
Voir le résumé public ComponentName startService (service d'intention) .
Ce n'est pas comme vérifier, je pense, car cela démarre le service, vous pouvez donc ajouter
stopService(someIntent);
sous le code.la source
if(startService(someIntent) != null)
vérifiera cela,IsserviceRunning
mais cela jouera également un nouveau service.la source
Un extrait de documents Android :
Pensez à ce hack comme "cinglant" le
Service
. Puisque nous pouvons diffuser de manière synchrone, nous pouvons diffuser et obtenir un résultat de manière synchrone , sur le thread d'interface utilisateur.Service
Activity
Le gagnant dans de nombreuses applications est, bien sûr, un champ booléen statique sur le service qui est défini sur
true
inService.onCreate()
et surfalse
inService.onDestroy()
car il est beaucoup plus simple.la source
J'ai légèrement modifié l'une des solutions présentées ci-dessus, mais en passant la classe au lieu d'un nom de chaîne générique, afin d'être sûr de comparer les chaînes provenant de la même méthode
class.getName()
et alors
la source
Class<? extends Service>
La bonne façon de vérifier si un service est en cours d'exécution est de simplement le demander. Implémentez un BroadcastReceiver dans votre service qui répond aux pings de vos activités. Enregistrez le BroadcastReceiver au démarrage du service et annulez-le lorsque le service est détruit. Depuis votre activité (ou n'importe quel composant), envoyez une intention de diffusion locale au service et s'il répond, vous savez qu'il est en cours d'exécution. Notez la différence subtile entre ACTION_PING et ACTION_PONG dans le code ci-dessous.
la source
Je veux juste ajouter une note à la réponse de @Snicolas. Les étapes suivantes peuvent être utilisées pour vérifier le service d'arrêt avec / sans appel
onDestroy()
.onDestroy()
appelé: Allez dans Paramètres -> Application -> Services en cours d'exécution -> Sélectionnez et arrêtez votre service.onDestroy()
non appelé: allez dans Paramètres -> Application -> Gérer les applications -> Sélectionnez et "Forcer l'arrêt" de votre application dans laquelle votre service s'exécute. Cependant, comme votre application est arrêtée ici, les instances de service seront également arrêtées.Enfin, je voudrais mentionner que l'approche mentionnée ici en utilisant une variable statique dans la classe singleton fonctionne pour moi.
la source
onDestroy
n'est pas toujours appelé au service donc c'est inutile!Par exemple: il suffit de relancer l'application avec un changement depuis Eclipse. L'application est fermée de force en utilisant SIG: 9.
la source
Tout d'abord, vous ne devez pas essayer d'accéder au service en utilisant ActivityManager. (Discuté ici )
Les services peuvent fonctionner seuls, être liés à une activité ou aux deux. La façon de vérifier dans une activité si votre service est en cours d'exécution ou non consiste à créer une interface (qui étend Binder) dans laquelle vous déclarez des méthodes que les deux, l'activité et le service, comprennent. Vous pouvez le faire en créant votre propre interface où vous déclarez par exemple "isServiceRunning ()". Vous pouvez ensuite lier votre activité à votre service, exécuter la méthode isServiceRunning (), le service vérifiera s'il s'exécute ou non et renvoie un booléen à votre activité.
Vous pouvez également utiliser cette méthode pour arrêter votre service ou interagir avec lui d'une autre manière.
J'ai utilisé ce tutoriel pour apprendre à implémenter ce scénario dans mon application.
la source
Encore une fois, une autre alternative que les gens pourraient trouver plus propre s'ils utilisent des intentions en attente (par exemple avec
AlarmManager
:Où se
CODE
trouve une constante que vous définissez en privé dans votre classe pour identifier les intentions en attente associées à votre service.la source
Vous trouverez ci-dessous un hack élégant qui couvre tous les
Ifs
. Ceci est réservé aux services locaux.Et puis plus tard:
la source
Version Xamarin C #:
la source
GetSystemService
.Pour le cas d'utilisation donné ici, nous pouvons simplement utiliser la
stopService()
valeur de retour de la méthode. Il retournetrue
s'il existe le service spécifié et il est tué. Sinon, il revientfalse
. Vous pouvez donc redémarrer le service si le résultat estfalse
sinon il est assuré que le service actuel a été arrêté. :) Il serait mieux si vous avez un oeil à ce .la source
Une autre approche utilisant kotlin. Inspiré des réponses des autres utilisateurs
Comme extension kotlin
Usage
la source
Dans kotlin, vous pouvez ajouter une variable booléenne dans l'objet compagnon et vérifier sa valeur dans la classe de votre choix:
Changer sa valeur lorsque le service est créé et détruit
la source
Dans votre sous-classe de service, utilisez un booléen statique pour obtenir l'état du service, comme illustré ci-dessous.
MyService.kt
MainActivity.kt
la source
Pour kotlin, vous pouvez utiliser le code ci-dessous.
la source
L'appel
la source
ActivityManager.getRunningServices
est déconseillé depuis Android OIl peut y avoir plusieurs services avec le même nom de classe.
Je viens de créer deux applications. Le nom du package de la première application est
com.example.mock
. J'ai créé un sous-package appelélorem
dans l'application et un service appeléMock2Service
. Son nom complet est donccom.example.mock.lorem.Mock2Service
.J'ai ensuite créé la deuxième application et un service appelé
Mock2Service
. Le nom du package de la deuxième application estcom.example.mock.lorem
. Le nom complet du service l'estcom.example.mock.lorem.Mock2Service
également.Voici ma sortie logcat.
Une meilleure idée est de comparer les
ComponentName
instances en raisonequals()
de laComponentName
comparaison des noms de package et des noms de classe. Et il ne peut pas y avoir deux applications avec le même nom de package installées sur un appareil.La méthode equals () de
ComponentName
.Nom du composant
la source
Veuillez utiliser ce code.
la source
Cela s'applique davantage au débogage du service d'intention car ils génèrent un thread, mais peuvent également fonctionner pour les services réguliers. J'ai trouvé ce fil grâce à Binging
Dans mon cas, j'ai joué avec le débogueur et trouvé la vue du thread. Cela ressemble à l'icône de puce dans MS Word. Quoi qu'il en soit, vous n'avez pas besoin d'être en mode débogueur pour l'utiliser. Cliquez sur le processus et cliquez sur ce bouton. Tous les services d'intention s'afficheront pendant leur exécution, au moins sur l'émulateur.
la source
Si le service appartient à un autre processus ou APK, utilisez la solution basée sur ActivityManager.
Si vous avez accès à sa source, utilisez simplement la solution basée sur un champ statique. Mais à la place, en utilisant un booléen, je suggère d'utiliser un objet Date. Pendant que le service est en cours d'exécution, mettez simplement à jour sa valeur sur «maintenant» et quand il a terminé, définissez-la sur null. À partir de l'activité, vous pouvez vérifier si sa valeur nulle ou la date est trop ancienne, ce qui signifie qu'elle n'est pas en cours d'exécution.
Vous pouvez également envoyer une notification de diffusion à partir de votre service pour indiquer que des informations supplémentaires telles que la progression sont affichées.
la source
À l'intérieur de TheServiceClass, définissez:
Puis dans onStartCommand (...)
Ensuite, appelez
if(TheServiceClass.serviceRunning == true)
de n'importe quelle classe.la source
stopService
. Au moins pour les services d'intention.onDestroy()
sera appelé immédiatement, maisonHandleIntent()
sera toujours en cours d'exécutionutilisation simple bind avec Don't create auto- voir ps. et mettre à jour ...exemple :
pourquoi ne pas utiliser? getRunningServices ()
Remarque: cette méthode est uniquement destinée au débogage ou à la mise en œuvre d'interfaces utilisateur de type gestion de service.
ps. la documentation Android est trompeuse j'ai ouvert un problème sur google tracker pour éliminer les doutes:
https://issuetracker.google.com/issues/68908332
comme nous pouvons le voir, le service de liaison appelle réellement une transaction via le classeur ActivityManager via les liants de cache de service - je vérifie quel service est responsable de la liaison, mais comme nous pouvons le voir, le résultat de la liaison est:
la transaction se fait via un classeur:
suivant:
cela est défini dans ActivityThread via:
ceci est appelé dans ActivityManagerService dans la méthode:
puis:
mais il n'y a pas de "fenêtre" d'activité et d'alarme seulement.
nous devons donc revenir pour appeler:
cela fait appel à travers:
qui conduit à :
et c'est une méthode native ....
je n'ai pas le temps maintenant de creuser en c donc jusqu'à ce que je dissèque l'appel reste je suspends ma réponse.
mais le meilleur moyen de vérifier si le service est en cours d'exécution est de créer une liaison (si la liaison n'est pas créée, le service n'existe pas) - et d'interroger le service sur son état via la liaison (en utilisant un indicateur interne stocké sur son état).
mise à jour 23.06.2018
j'ai trouvé ceux intéressants:
en bref :)
"Fournir un classeur à un service déjà lié. Cette méthode est synchrone et ne démarre pas le service cible s'il n'est pas présent."
public IBinder peekService (service Intent, StringolvedType, String callingPackage) lève RemoteException;
la source
Ma conversion en kotlin des
ActivityManager::getRunningServices
réponses basées. Mettez cette fonction dans une activité-la source
Il vous est possible d'utiliser ces options à partir des options du développeur Android pour voir si votre service fonctionne toujours en arrière-plan.
la source
Allez-y doucement les gars ... :)
Je pense que la solution la plus appropriée consiste à détenir une paire clé-valeur pour
SharedPreferences
savoir si le service fonctionne ou non.La logique est très droite; à n'importe quel poste souhaité dans votre classe de service; mettez une valeur booléenne qui vous servira d'indicateur pour savoir si le service est en cours d'exécution ou non. Lisez ensuite cette valeur où vous le souhaitez dans votre application.
Un exemple de code que j'utilise dans mon application est ci-dessous:
Dans ma classe Service (Un service pour Audio Stream), j'exécute le code suivant lorsque le service est en service;
Ensuite, dans toute activité de mon application, je vérifie l'état du service à l'aide du code suivant;
Pas d'autorisations spéciales, pas de boucles ... Facile, solution propre :)
Si vous avez besoin d'informations supplémentaires, veuillez vous référer au lien
J'espère que cela t'aides.
la source
onDestroy
n'est pas toujours appelé lorsque le service est tué. Par exemple, j'ai vu mes services tués dans des situations de mémoire faible sansonDestroy
être appelé.