web-dev-qa-db-fra.com

Android Background Service redémarre lorsque l'application est tuée

Je développe une application dans laquelle un service d'arrière-plan est créé pour collecter les données des capteurs. Je démarre le service à partir de mon activité:

startService(new Intent(this, MyService.class));

J'ai créé le service, donc si l'application est détruite, le service d'arrière-plan continue de collecter des données. J'ai essayé cela, et cela a fonctionné dans une certaine mesure. Mon problème est que lorsque je tue l'application, le service semble redémarrer car le service onCreate() et les méthodes onStart() sont appelés. Existe-t-il un moyen de ne pas redémarrer le service, s'il vous plaît?

MISE À JOUR:

Comme suggéré dans une réponse ci-dessous, j'ai ajouté la méthode suivante dans le service mais pas de chance.

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    return START_NOT_STICKY;
}
37
duncanportelli

Cela dépend de la valeur retournée dans onStartCommand.

Vous devez retourner START_NOT_STICKY

Selon la documentation :

Pour les services démarrés, il existe deux modes de fonctionnement principaux supplémentaires qu'ils peuvent décider d'exécuter, en fonction de la valeur qu'ils renvoient de onStartCommand (): START_STICKY est utilisé pour les services qui sont explicitement démarrés et arrêtés selon les besoins, tandis que START_NOT_STICKY ou START_REDELIVER_INTENT sont utilisés pour les services qui ne doivent rester en cours d'exécution que lors du traitement des commandes qui leur sont envoyées

En bref: si vous retournez START_STICKY, le service est recréé chaque fois que les ressources sont disponibles. Si vous retournez START_NOT_STICKY, vous devez réactiver le service en envoyant une nouvelle intention.

Étant donné que tout cela a déclenché ma curiosité, j'ai créé un exemple d'application pour le tester. Vous pouvez trouver le Zip avec toutes les sources ici Il y a un bouton startService et un bouton stopService qui font ce que vous attendez d'eux. Le service renvoie START_NOT_STICKY dans onStartCommand. J'ai placé des toasts dans onCreate, onStartCommand et onDestroy.

Voici ce qui se passe:

  • Si j'appuie sur start, onCreate et onStart sont appelés
  • Si j'appuie sur stop, onDestroy est déclenché
  • Si j'appuie deux fois sur start, onCreate est appelé une fois et onStartCommand deux fois

Il se comporte donc comme on pourrait s'y attendre.

Si je démarre le service et tue l'application comme vous l'avez décrit, onDestroy n'est pas appelé mais ni onCreate ni onStart.

Si je reviens à l'application et que j'appuie à nouveau sur start, onCreate est appelé , ce qui signifie que, comme je l'ai écrit précédemment, START_NOT_STICKY empêche le redémarrage du service automatiquement.

Je suppose que vous avez quelque chose d'autre dans votre application qui redémarre le service (peut-être une intention en attente).

20
fedepaol

L'application et le service vivent sur le même processus, ce qui signifie que lorsque l'application est supprimée, votre service l'est également. La modification de la valeur de retour de onStartCommand n'affecte pas ce processus. Il indique simplement au service de démarrer/arrêter lorsque vous le dites ou lorsqu'il a fini de faire ce qu'il doit. Comme mentionné dans votre commentaire à votre message d'origine, le définir comme un processus de premier plan a fonctionné, mais cela oblige vraiment le service à avoir une priorité élevée, sans résoudre le problème.

Pour modifier le service afin qu'il soit tué séparément et en supposant qu'il s'agit d'un service démarré plutôt que d'un service lié en raison de l'utilisation de onStartCommand, spécifiez un nom de processus dans le manifeste pour ce service.

Dans le Guide du développeur de processus et de threads :

L'entrée de manifeste pour chaque type d'élément composant— <activity>, <service>, <receiver>, and <provider>— prend en charge un attribut Android: process qui peut spécifier un processus dans lequel ce composant doit s'exécuter. Vous pouvez définir cet attribut de sorte que chaque composant s'exécute dans son propre processus ou que certains composants partagent un processus tandis que d'autres ne le font pas. Vous pouvez également définir Android: processus de sorte que les composants de différentes applications s'exécutent dans le même processus, à condition que les applications partagent le même ID utilisateur Linux et soient signées avec les mêmes certificats.

Android peut décider d'arrêter un processus à un moment donné, lorsque la mémoire est insuffisante et requise par d'autres processus qui servent plus immédiatement l'utilisateur. Les composants d'application en cours d'exécution dans le processus tué sont par conséquent détruits. Un processus est redémarré pour ces composants lorsqu'il y a encore du travail à faire pour eux.

De <service> dans le fichier manifeste :

Android: processus

Nom du processus où le service doit s'exécuter. Normalement, tous les composants d'une application s'exécutent dans le processus par défaut créé pour l'application. Il porte le même nom que le package d'application. L'attribut de processus de l'élément peut définir une valeur par défaut différente pour tous les composants. Mais le composant peut remplacer la valeur par défaut avec son propre attribut de processus, vous permettant de répartir votre application sur plusieurs processus.

Si le nom attribué à cet attribut commence par deux points (':'), un nouveau processus, privé de l'application, est créé lorsque cela est nécessaire et le service s'exécute dans ce processus. Si le nom du processus commence par un caractère minuscule, le service s'exécutera dans un processus global de ce nom, à condition qu'il soit autorisé à le faire. Cela permet aux composants de différentes applications de partager un processus, ce qui réduit l'utilisation des ressources.

Je ne sais pas pourquoi l'autre réponse qui a mentionné cela a été rejetée. J'ai utilisé cette méthode dans le passé et, aujourd'hui, j'ai créé une simple application d'activité avec un service sur un processus différent juste pour m'assurer que je n'étais pas fou. J'ai utilisé Android Device Monitor pour tuer le processus de l'application. Vous pouvez voir les deux, des processus distincts dans ADM et pouvez voir que lorsque le processus de l'application est tué, le service ne l'est pas.

4
Plumbus

Start not sticky ne fonctionne pas au-dessus de KitKat, et l'autre onTaskRemoved ne fonctionne pas au-dessus de Marshmellow. onTaskRemoved pourrait être utilisé par certaines exceptions gérées. N'a pas travaillé là-dessus. Mais essayez celui-là.

1
Minkoo

Si vous utilisez un IntentService, il a un

onHandleIntent() 

méthode où vous devez placer le code qui doit être exécuté. Il est exécuté dans un thread séparé (pas un thread d'interface utilisateur dans lequel votre application s'exécute), votre application ne devrait donc pas l'affecter. Une fois l'exécution du code terminée, le thread se termine et le service est arrêté automatiquement.

0
Marcin S.

Je sais qu'il est bien tard pour répondre à cette question, mais cela peut être utile à d'autres. Cela m'a vraiment aidé pour mon application Music Player.

S'il y a des services qui peuvent être perturbateurs ou peuvent affecter l'expérience utilisateur comme la musique, etc., alors dans ce cas, vous devez utiliser Notification et lorsque le service est démarré avec succès, puis créez la Notification et utilisez la fonction

startForeground(int Notification_id,Notification);

Cela exécutera votre service en arrière-plan sans redémarrer ni réinvoquer ses méthodes

https://developer.Android.com/reference/Android/app/Service.html

0
abissa