web-dev-qa-db-fra.com

Android O et les limites de fond empêche la notification d'alarme simple

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)

12
Zordid

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 ... :( 

8
Zordid

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+.

6
CommonsWare

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.

0
MOHIT KUMAR