Ma propre application utilise exactement la même technique que celle illustrée par l'application Google I/O de 2016. voir source
Je dois rappeler aux utilisateurs à un moment très précis - en utilisant une notification.
Pour cela, j'utilise la AlarmManager
pour réveiller le périphérique au bon moment:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, alarmTime, pendingIntent);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KitKat) {
am.setExact(AlarmManager.RTC_WAKEUP, alarmTime, pendingIntent);
} else {
am.set(AlarmManager.RTC_WAKEUP, alarmTime, pendingIntent);
}
La pendingIntent
est créée comme ceci:
final Intent intent = new Intent(MyAlarmService.ACTION_NOTIFY_RIDE, null, this, MyAlarmService.class);
pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
Maintenant, ma classe MyAlarmService
est une simple IntentService
qui gère la mise en éveil uniquement dans le but de créer une notification pour l'utilisateur.
Le message que je reçois dans le journal est le suivant:
W/ActivityManager: Background start not allowed: service Intent { act=xxx.xxx.xxx.action.NOTIFY_RIDE flg=0x4 cmp=xxx.xxx.xxx./xxx.xxx.xxx.service.MyAlarmService (has extras) }
Maintenant, la propre implémentation de Google est évidemment cassée - bien que je ne veuille pas faire de gros travaux de fond, je ne peux plus utiliser cette technique. Mais comment suis-je censé réveiller l'utilisateur à un moment très précis? (Pensez à mon application comme un réveil)
La réponse à ma question est claire et simple:
Au lieu d'utiliser un service pour afficher la notification (comme Google le fait dans son IO Application programmée!), Utilisez un BroadcastReceiver!
Je ne sais pas pourquoi Google a utilisé IntentService, mais maintenant sous Android O, cela ne fonctionne tout simplement plus en raison des limites d'exécution en arrière-plan.
Un BroadcastReceiver, bien que de toute évidence, puisse toujours fonctionner pendant un bref instant et afficher une notification.
Des points bonus si quelqu'un pouvait me dire pourquoi Google utilisait IntentService en premier lieu ... cela m'a pris énormément de temps à comprendre, car je pensais que Google savait ce qu'il faisait ... :(
Mais comment suis-je censé réveiller l'utilisateur à un moment très précis? (Pensez à mon application comme un réveil)
Tout d'abord, votre code ne sera pas exact. Si l'appareil est en mode veille, je m'attendrais au mieux à +/- 10 minutes. Si vous voulez un timing exact et que votre application est vraiment un réveil, utilisez setAlarmClock()
.
Pour votre code existant, utilisez getForegroundService()
au lieu de getService()
dans l'API de niveau 26+.
Vous pouvez même envisager que SyncAdapter/Job Scheduler s'exécute périodiquementexécuter la même logique métier . Et pour définir une nouvelle synchronisation périodique que vous pouvez avoir lors du premier lancement de l'application.