J'ai lu à peu près toutes les réponses Stackoverflow disponibles sur ce sujet, mais aucune d'entre elles n'a fonctionné.
Problème: chaque fois que mon appareil est en mode veille pendant au moins une heure, le service est désactivé
Renvoyer START_STICKY
depuis onStartCommand()
et utiliser startForeground()
public int onStartCommand(Intent intent, int flags, int startId) {
notification = makeStickyNotification(); //I've simplified the irrelevant code, obviously this would be a real notification I build
startForeground(1234, notification);
return START_STICKY;
}
Cela fonctionne correctement et redémarre même mon service lorsque le périphérique manque de mémoire, mais cela ne suffit pas pour résoudre le problème qui se produit lorsque mon périphérique se met en veille pendant un certain temps.
Utiliser Alarm Manager dans onCreate()
de mon activité et dans onStartCommand()
de mon service pour appeler un récepteur de diffusion qui appelle mon service
Intent ll24 = new Intent(this, AlarmReceiver.class);
PendingIntent recurringLl24 = PendingIntent.getBroadcast(this, 0, ll24, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarms = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarms.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000*60, recurringLl24); // Every minute
Cela permet de garder mon service actif, mais encore une fois, cela ne résout pas mon problème
Utiliser Schedule Task Executor pour le garder en vie
if (scheduleTaskExecutor == null) {
scheduleTaskExecutor = Executors.newScheduledThreadPool(1);
scheduleTaskExecutor.scheduleAtFixedRate(new mainTask(), 0, 1, TimeUnit.SECONDS);
}
...
class mainTask implements Runnable {
public void run() {
// 1 Second Timer
}
}
Cela maintient également le service actif, mais ne le maintient pas en vie après un long sommeil.
Manifeste de tâche séparée
Android:launchMode="singleTop"
Cela n'a rien fait
Comment puis-je (1) tester ce problème sans avoir à mettre mon téléphone en veille et à vérifier toutes les heures et (2) à assurer le bon fonctionnement de mon service malgré le périphérique en veille?
Le mystère du meurtre a été résolu, et je sais ce qui a tué mon service. Voici ce que j'ai fait:
startsticky
, startforeground
, alarmmanager
, scheduleTaskExecutor
, et même wakelock
étaient incapables de sauver mon service, j'ai réalisé que l'assassin ne pouvait pas être le système Android, car j'avais pris toutes les mesures possibles pour empêcher le système de tuer mon service et il serait toujours tué. J'ai réalisé que je devais rechercher un autre suspect, car le service ne mourait pas à cause du système. Pour cela, je devais mener une enquête. J'ai lancé la commande suivante:
adb Shell dumpsys activity processes > tmp.txt
Cela me donnerait un journal détaillé de tous les processus en cours d'exécution et de leurs priorités système. tmp.txt
serait essentiellement le détective dans ce mystère de meurtre.
J'ai parcouru le dossier avec beaucoup de détails. Il semblait que le système donnait la priorité à mon service:
Proc #31: adj=prcp /FS trm= 0 2205:servicename.service/uID (fg-service)
La ligne ci-dessus indique la priorité exacte d'un processus en cours d'exécution sur le périphérique Android. adj=prcp
signifie que le service est un service de premier plan visible.
À ce stade, je me suis rendu compte que mon service doit rencontrer une erreur quelques heures après avoir exécuté, alors je le laisse courir et mourir. Après sa mort, j’ai produit à nouveau une dumpsys
pour examiner l’erreur:
tmp.txt
. Excité, j'ai fait défiler jusqu'au dumpsys
et résolu le mystère!com.curlybrace.ruchir.appName.MyService $ 2.onForeground (MyService.Java:199) sur com.rvalerio.fgchecker.AppChecker $ 2.de courir (AppChecker.Java:118) sur Android. os.Handler.handleCallback (Handler.Java:751) à Android.os.Handler.dispatchMessage (Handler.Java:95) à Android.os.Looper.loop (Looper.Java: 154) Sur Android.app.ActivityThread.main (ActivityThread.Java:6123) Sur Java.lang.reflect.Method.invoke (Méthode native) Sur com.Android .internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.Java:867) sur com.Android.internal.os.ZygoteInit.main (ZygoteInit.Java:757)
La trace de la pile qui a tué mon service était affichée à cet endroit! Essentiellement, une variable qui vérifierait l'application utilisée au premier plan deviendrait nulle après quelques heures d'inactivité, ce qui provoquerait une exception et tuerait le service!
À retenir: Si votre service est tué et que vous avez fait tout votre possible pour vous assurer qu'il ne devrait pas être tué, effectuez une dumpsys
et examinez la gravité de l'activité de votre appareil. processus. Je vous garantis que vous trouverez le problème de cette façon.
Je voudrais toujours avoir la prime attribuée à @Khemraj car sa réponse pourrait être une excellente solution pour quelqu'un qui n'a pas démarré son service correctement. Cependant, j'accepte cette réponse car c'est la solution qui a réellement résolu le problème.
Votre service a été tué par mode Doze ou veille d'Android. Cela a été introduit dans Android 6.0 (API de niveau 23).
Somnolence restrictions
Les restrictions suivantes s'appliquent à vos applications en Doze:
- L'accès au réseau est suspendu.
- Le système ignore les verrous de réveil.
- Les alarmes standard
AlarmManager
y comprissetExact()
etsetWindow()
) sont différées à la fenêtre de maintenance suivante.- Si vous devez définir des alarmes qui se déclenchent à Doze, utilisez
setAndAllowWhileIdle()
ousetExactAndAllowWhileIdle()
.- Les alarmes définies avec
setAlarmClock()
continuent à se déclencher normalement - le système quitte Doze peu de temps avant le déclenchement de ces alarmes.- Le système n’effectue pas d’analyses Wi-Fi.
- Le système ne permet pas aux adaptateurs de synchronisation de s'exécuter. Le système n'autorise pas
JobScheduler
à s'exécuter.
_ (Le système a donc ignoré votre Alarm Clocks, Scheduler
, etc.
Pour améliorer l'expérience utilisateur, Android 8.0 (API niveau 26) impose Des limites à ce que les applications peuvent faire lorsqu'elles s'exécutent en arrière-plan.
Néanmoins, si l'application doit toujours exécuter son service, nous pouvons créer un service de premier plan.
Limitations du service en arrière-plan:Lorsqu'une application est inactive, il existe des limites À son utilisation des services en arrière-plan. Ceci ne s'applique pas aux services au premier plan , Qui sont plus perceptibles par l'utilisateur.
Créez donc un service de premier plan. Dans lequel vous placerez un notification pour l'utilisateurpendant que votre service est en cours d'exécution. Voir cette réponse (Il y en a beaucoup d'autres)
Et maintenant, si vous ne voulez pas de notification pour votre service. Une solution est pour ça.
Vous pouvez créer une tâche périodique qui démarrera votre service. Le service fera son travail et s’arrêtera lui-même. De ce fait, votre application ne sera pas considérée comme une batterie épuisante.
Vous pouvez créer une tâche périodique avec Alarm Manager , Planificateur de tâches , Evernote-Jobs ou Work Manager .
J'ai créé un service permanent avec Work-Manager, qui fonctionne parfaitement.
onDestroy () n'est vraiment pas fiable et ne sera pas appelé souvent. Idem pour onLowMemory () callbacks. Il n'y a aucun moyen de prendre un rappel garanti si Android décide de tuer votre processus ou si l'utilisateur décide de forcer Arrêter votre application.
Il est normal que le périphérique utilisateur passe en mode veille, votre service meurt. Lisez à propos de wakelocks . Essayez quelque chose comme ça à votre service: In manifest:
<uses-permission Android:name="Android.permission.WAKE_LOCK" />
En service:
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"tag");
wakeLock.acquire();
Mais c’est vraiment difficile pour l’utilisateur et totalement anti-modèle dans le monde Android, à cause de la consommation de la batterie.
Une autre option consiste à déclencher un service comme toutes les 10 minutes. Définissez l'intention en attente sur WakefulBroadcastReceiver (où vous pouvez démarrer votre service) et planifiez-la avec le gestionnaire d'alarmes avec l'indicateur RTC_WAKE_UP
Le mode assoupi tue les services pour économiser la batterie. La seule solution valable pour vous consiste à créer un service de premier plan dans Oreo et au-dessus. https://developer.Android.com/about/versions/oreo/background
À partir du SDK 26, un service doit avoir son "MainActivity" relative au premier plan OR ce service doit être démarré comme au premier plan à l'aide de "startForegroundService ()". Le "startForeground ()" ne fonctionne pas comme prévu si le SDK cible est 26+ mais besoin de l'autre manière que je viens d'expliquer.
Après cela, vous pouvez utiliser le code suivant pour Kill et redémarrer l'application à partir de zéro (oui, même le service est tué de cette manière):
Intent mStartActivity = new Intent(context, StartActivity.class);
int mPendingIntentId = 123456;
PendingIntent mPendingIntent = PendingIntent.getActivity(context, mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager mgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
System.exit(0);