Remarque: J'ai essayé diverses solutions qui sont écrites ici sur StackOverflow (exemple ici ). Veuillez ne pas fermer cela sans vérifier si votre solution à partir de ce que vous avez trouvé fonctionne en utilisant le test que j'ai écrit ci-dessous.
Contexte
Il existe une exigence sur l'application, que l'utilisateur définit un rappel à planifier à une heure spécifique, donc lorsque l'application est déclenchée à ce moment, elle fait quelque chose de minuscule en arrière-plan (juste une opération de requête DB), et affiche un simple notification, pour parler du rappel.
Dans le passé, j'utilisais un code simple pour définir quelque chose à planifier à une heure relativement spécifique:
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val pendingIntent = PendingIntent.getBroadcast(context, requestId, Intent(context, AlarmReceiver::class.java), PendingIntent.FLAG_UPDATE_CURRENT)
when {
VERSION.SDK_INT >= VERSION_CODES.KITKAT -> alarmManager.setExact(AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
else -> alarmManager.set(AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
}
class AlarmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log.d("AppLog", "AlarmReceiver onReceive")
//do something in the real app
}
}
Usage:
val timeToTrigger = System.currentTimeMillis() + java.util.concurrent.TimeUnit.MINUTES.toMillis(1)
setAlarm(this, timeToTrigger, 1)
Le problème
J'ai maintenant testé ce code sur des émulateurs sur de nouvelles versions d'Android et sur Pixel 4 avec Android 10, et il ne semble pas se déclencher, ou peut-être qu'il se déclenche très longtemps après ce que je lui ai fourni. Je suis bien conscient du comportement terrible que certains OEM ont ajouté à la suppression des applications des tâches récentes, mais celle-ci se trouve à la fois sur les émulateurs et sur le périphérique Pixel 4 (stock).
J'ai lu dans les documents sur la définition d'une alarme, qu'elle a été restreinte pour les applications afin qu'elle ne se produise pas trop souvent, mais cela n'explique pas comment définir une alarme à un moment précis, et cela n'explique pas comment se fait de Google app de l' horloge réussit à le faire.
Non seulement cela, mais d'après ce que je comprends, cela dit que les restrictions devraient être appliquées en particulier pour l'état de faible puissance de l'appareil, mais dans mon cas, je n'avais pas cet état, à la fois sur l'appareil et sur les émulateurs. J'ai réglé les alarmes pour qu'elles se déclenchent dans environ une minute à partir de maintenant.
Voyant que de nombreuses applications de réveil ne fonctionnent plus comme avant, je pense qu'il manque quelque chose dans les documents. Un exemple de telles applications est l' application Timely populaire qui a été achetée par Google mais n'a jamais reçu de nouvelles mises à jour pour gérer les nouvelles restrictions, et maintenant les utilisateurs veulent la récupérer. . Cependant, certaines applications populaires fonctionnent bien, comme celle-ci .
Ce que j'ai essayé
Pour tester le fait que l'alarme fonctionne, j'effectue ces tests lorsque j'essaie de déclencher l'alarme dans une minute à partir de maintenant, après avoir installé l'application pour la première fois, le tout pendant que l'appareil est connecté au PC (pour voir les journaux):
- Testez lorsque l'application est au premier plan, visible par l'utilisateur. - a pris 1-2 minutes.
- Test lorsque l'application a été envoyée en arrière-plan (en utilisant le bouton d'accueil, par exemple) - a pris environ 1 minute
- Testez quand la tâche de l'application a été supprimée des tâches récentes. - J'ai attendu plus de 20 minutes et je n'ai pas vu l'alarme se déclencher, écrivant dans les journaux.
- Comme # 3, mais aussi éteignez l'écran. Ce serait probablement pire ...
J'ai essayé d'utiliser les choses suivantes, tout ne fonctionne pas:
alarmManager.setAlarmClock(AlarmManager.AlarmClockInfo(timeToTrigger, pendingIntent), pendingIntent)
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
combinaison de l'un des éléments ci-dessus, avec:
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) alarmManager.setWindow(AlarmManager.RTC_WAKEUP, 0, 60 * 1000L, pendingIntent)
J'ai essayé d'utiliser un service au lieu de BroadcastReceiver. Également essayé sur un processus différent.
J'ai essayé de faire en sorte que l'application soit ignorée de l'optimisation de la batterie (n'a pas aidé), mais comme d'autres applications n'en ont pas besoin, je ne devrais pas l'utiliser non plus.
Essayé en utilisant ceci:
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP)
alarmManager.setAlarmClock(AlarmManager.AlarmClockInfo(timeToTrigger, pendingIntent), pendingIntent)
AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
- J'ai essayé d'avoir un service qui aura un déclencheur de onTaskRemoved , pour replanifier l'alarme là-bas, mais cela n'a pas aidé non plus (le service a bien fonctionné cependant).
Quant à l'application Horloge de Google, je n'ai rien vu de spécial à part qu'elle montre une notification avant d'être déclenchée, et je ne la vois pas non plus dans la section "non optimisée" de l'écran des paramètres d'optimisation de la batterie.
Voyant que cela semble être un bug, j'ai signalé à ce sujet ici , y compris un exemple de projet et une vidéo pour montrer le problème.
J'ai vérifié plusieurs versions de l'émulateur, et il semble que ce comportement soit parti de l'API 27 (Android 8.1 - Oreo). En regardant les documents , je ne vois pas que AlarmManager soit mentionné, mais à la place, il a été écrit sur divers travaux d'arrière-plan.
Questions
Comment définissons-nous quelque chose à déclencher à une heure relativement exacte de nos jours?
Comment se fait-il que les solutions ci-dessus ne fonctionnent plus? Suis-je en train de manquer quelque chose? Autorisation? Peut-être que je suis censé utiliser un Worker à la place? Mais cela ne signifierait-il pas que cela pourrait ne pas se déclencher du tout?
Comment l'application "Horloge" de Google surmonte-t-elle tout cela et se déclenche-t-elle de toute façon à l'heure exacte, toujours, même si elle a été déclenchée il y a une minute? Est-ce uniquement parce que c'est une application système? Que faire si elle est installée en tant qu'application utilisateur, sur un appareil qui ne l'a pas intégré?
Si vous dites que c'est parce que c'est une application système, j'ai trouvé une autre application qui peut déclencher une alarme deux fois en 2 minutes, ici , bien que je pense qu'elle utilise parfois un service de premier plan.
EDIT: créé un petit dépôt Github pour essayer des idées, ici .
EDIT: a finalement trouvé un échantillon qui est à la fois open-source et n'a pas ce problème. Malheureusement, c'est très complexe et j'essaie toujours de comprendre ce qui le rend si différent (et quel est le code minimal que je devrais ajouter à mon POC) qui permet à ses alarmes de rester programmées après la suppression de l'application des tâches récentes