Le problème ici semble ne pas se produire sur les ROMs basées sur AOSP. C'est-à-dire que je peux facilement recréer ce problème sur une ROM basée sur CyanogenMod 11, mais sur une ROM AOSP (et sur un émulateur), START_STICKY se comporte exactement comme je m'y attendais. Cela dit, je vois des rapports de personnes sur des Nexus 5 qui semblent avoir ce comportement, donc peut-être que c'est encore un problème dans AOSP.
Sur un émulateur et sur une ROM AOSP, je vois ce qui suit dans un logcat lorsque je fais un 'kill 5838' sur le processus (comme je m'y attendais) :
12-22 18:40:14.237 D/Zygote ( 52): Process 5838 terminated by signal (15)
12-22 18:40:14.247 I/ActivityManager( 362): Process com.xxxx (pid 5838) has died.
12-22 18:40:14.247 W/ActivityManager( 362): Scheduling restart of crashed service com.xxxx/com.xxxx.NotifyingService in 5000ms
12-22 18:40:19.327 I/ActivityManager( 362): Start proc com.xxxx for service xxxx.pro/com.xxxx.NotifyingService: pid=5877 uid=10054 gids={50054, 3003, 3002, 1028}
Je constate le même comportement de redémarrage si je termine la tâche en faisant glisser la souris depuis la liste des tâches récentes. C'est donc une bonne chose - cela signifie que le code AOSP de base se comporte comme il l'a fait dans les niveaux précédents.
Je regarde le code de service de Cyanogenmod pour essayer de comprendre pourquoi les choses ne sont pas programmées pour le redémarrage - pas encore de chance. Il semble qu'il devrait le reprogrammer. Cyanogenmod utilise une carte de service, ce qui n'est pas le cas d'AOSP, mais je ne sais pas si c'est un problème ou non (douteux). https://github.com/CyanogenMod/android_frameworks_base/blob/cm-11.0/services/java/com/Android/server/am/ActiveServices.java#L2092
Une solution de contournement plutôt artisanale consiste à utiliser un mécanisme similaire à celui de votre service d'alarme onTaskRemoved pour activer une alarme pour X minutes plus tard. Ensuite, toutes les quelques minutes, pendant que votre application est en fonctionnement, vous pouvez réinitialiser l'alarme - de sorte qu'elle ne se déclenche que si les choses ont vraiment été tuées et non redémarrées. Ce n'est pas infaillible - l'utilisation d'un Handler vous donne du temps de fonctionnement par rapport au service d'alarme qui utilise le temps réel, il est donc possible que votre alarme se déclenche même si elle a été réglée à un moment plus long que votre handler de 'reset'. Mais si vous définissez une intention supplémentaire, vous pouvez choisir d'ignorer la commande onStartCommand si votre service était déjà en cours d'exécution, ce qui en fait un noop.
Je ne suis pas du tout un fan du hack suivant - mais il ne devrait pas faire de mal. Si l'utilisateur effectue une fermeture forcée explicite, alors le gestionnaire d'alarmes détruira toutes les alarmes définies afin que le service ne redémarre pas (ce que l'utilisateur souhaite).
Tout d'abord, créez une méthode d'aide qui déclenchera une alarme pendant 20 minutes, ce qui entraînera le déclenchement de la commande onStartCommand pour votre service. Toutes les 2 minutes, un Handler réinitialisera l'alarme de 20 minutes. Si le gestionnaire s'exécute dans les 20 minutes en temps réel, l'alarme ne se déclenchera jamais. L'exécution du gestionnaire n'est pas garantie si l'appareil est endormi (ce qui est une bonne chose).
private void ensureServiceStaysRunning() {
// KitKat appears to have (in some cases) forgotten how to honor START_STICKY
// and if the service is killed, it doesn't restart. On an emulator & AOSP device, it restarts...
// on my CM device, it does not - WTF? So, we'll make sure it gets back
// up and running in a minimum of 20 minutes. We reset our timer on a handler every
// 2 minutes...but since the handler runs on uptime vs. the alarm which is on realtime,
// it is entirely possible that the alarm doesn't get reset. So - we make it a noop,
// but this will still count against the app as a wakelock when it triggers. Oh well,
// it should never cause a device wakeup. We're also at SDK 19 preferred, so the alarm
// mgr set algorithm is better on memory consumption which is good.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
// A restart intent - this never changes...
final int restartAlarmInterval = 20*60*1000;
final int resetAlarmTimer = 2*60*1000;
final Intent restartIntent = new Intent(this, NotifyingService.class);
restartIntent.putExtra("ALARM_RESTART_SERVICE_DIED", true);
final AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Handler restartServiceHandler = new Handler()
{
@Override
public void handleMessage(Message msg) {
// Create a pending intent
PendingIntent pintent = PendingIntent.getService(getApplicationContext(), 0, restartIntent, 0);
alarmMgr.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + restartAlarmInterval, pintent);
sendEmptyMessageDelayed(0, resetAlarmTimer);
}
};
restartServiceHandler.sendEmptyMessageDelayed(0, 0);
}
}
Dans votre onCreate, vous pouvez appeler cette méthode. De même, dans votre onStartCommand, assurez-vous d'ignorer cette méthode si votre service est déjà opérationnel. EG :
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
...
if ((intent != null) && (intent.getBooleanExtra("ALARM_RESTART_SERVICE_DIED", false)))
{
Log.d(TAG, "onStartCommand after ALARM_RESTART_SERVICE_DIED");
if (IS_RUNNING)
{
Log.d(TAG, "Service already running - return immediately...");
ensureServiceStaysRunning();
return START_STICKY;
}
}
// Do your other onStartCommand stuff..
return START_STICKY;
}
0 votes
Tout d'abord, votre service fonctionne-t-il sur le même processus que votre application ? Si c'est le cas, c'est que lorsque votre application est tuée, le Service l'est aussi. Essayez donc d'exécuter votre Service dans un processus différent, voici le lien pour vous : vogella.com/articles/AndroidServices/article.html
0 votes
J'ai essayé de l'exécuter sur le même processus et sur un processus différent. Même résultat.
0 votes
Il semble qu'ils aient copié le comportement d'iOS 7. Si vous faites glisser une application, son processus est interrompu et elle ne sera plus autorisée à exécuter quoi que ce soit en arrière-plan, y compris ses services, jusqu'à ce que vous relanciez manuellement l'application ou redémarriez l'appareil.
0 votes
De quoi Je peux dire la description du bug de l'AOSP #63793 est correct : à partir de 4.4(.2),
START_STICKY
ne seront pas redémarrés, il n'y aura pas de "Scheduling restart of crashed service
entrée de journal ". La version 4.3 n'est pas concernée, mais il s'agit d'un problème lié à l'AOSP, et non d'un problème introduit par les mods (par exemple CM), car j'ai pu le reproduire avec l'émulateur AOSP. Je ne pense pas que ce soit un changement prévu.0 votes
Après des semaines de recherches, j'ai trouvé la solution dans cette réponse : stackoverflow.com/a/29351792/5247630