Уведомления Android, запускаемые диспетчером сигналов тревоги, не срабатывают, когда приложение находится в режиме ожидания

У меня следующие требования. Пользователь должен иметь возможность запланировать повторяющееся напоминание в моем приложении, которое будет запускать push-уведомление в точное время каждый день.

Это один из тех вопросов, которые, как я надеялся, я в конечном итоге не отправлю, поскольку при его написании были рекомендованы аналогичные вопросы. Однако несколько членов команды часами просматривали документацию для разработчиков Android и Stackoverflow, и мы, похоже, не приблизились к ответу, так что вот и мы.

Если я создам напоминание и настрою запускать уведомление через 5 минут в будущем, уведомление сработает нормально.

Я подозреваю, что это может быть проблема, вызванная изменениями в энергосбережении, блокировке пробуждения и т. Д., Введенными в Android P, поскольку у нас не было этой проблемы до обновления нашего целевого SDK до 28. При этом я не уверен, что это Единственная проблема, но я могу постоянно воспроизводить проблему на Pixel и Pixel 3 XL под управлением Android P.

Пример, когда уведомление не запускается, происходит, когда, например, пользователь устанавливает напоминание на какое-то время посреди ночи (предположительно, когда пользователь спит и, следовательно, не будет использовать телефон в течение нескольких часов). Эти напоминания не срабатывают никогда.

В настоящее время я пытаюсь сделать это с помощью диспетчера аварийных сигналов.

Эта проблема похожа на другой вопрос, в котором используется setRepeating Метод, который мы нашли, не работает. Вместо этого мы используем метод setExactAndAllowWhileIdle диспетчера сигналов тревоги. Мы также попробовали ту же реализацию с менеджерами тревог setAlarmClock, который, согласно документации Android," будет разрешен запускаться, даже если система находится в режиме ожидания с низким энергопотреблением (также известный как дремота) ", однако это также не увенчалось успехом.

Я подозреваю, что причина, по которой это не работает, заключается в том, что setExactAndAllowWhileIdle не срабатывает, когда телефон находится в режиме ожидания, аналогично проблемам, выраженным в этот вопрос. В этом вопросе рекомендуется использовать Firebase JobDispatcher, но поскольку это внутреннее уведомление, я должен запускать уведомление с сетевым подключением или без него, что, похоже, исключает Firebase JobDispatcher в качестве опции. Этот вопрос также указывает на то, что как только телефон выходит из спящего режима, пользователь получает уведомление, однако мы никогда не получаем уведомление, они, похоже, потеряны из-за отсутствия лучшего термина.

Я добавил разрешение блокировки пробуждения в свой AndroidManifest.xml:

<uses-permission android:name="android.permission.WAKE_LOCK" />

Вот как мой приемник регистрируется в AndroidManifest.xml

<receiver android:name="com.myapp.receiver.AlarmReceiver">
    </receiver>

Вот моя текущая реализация:

Ожидающее намерение обработки уведомлений

Intent i = new Intent(context, ScheduleAllReceiver.class);
    PendingIntent scheduleAllPendingIntent = PendingIntent.getBroadcast(context, SCHEDULER_DAILY_ALL, i, PendingIntent.FLAG_UPDATE_CURRENT);

Впоследствии я вызываю метод createAlarm следующим образом

createAlarm(context, scheduleAllPendingIntent, calendar.getTimeInMillis());

Создание будильников

public static void createAlarm(Context context, PendingIntent pendingIntent, long timeinMilli) {
    AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);

    if(alarmManager != null) {

        if (Build.VERSION.SDK_INT >= 23) {
            alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeinMilli, pendingIntent);
        } else {
            alarmManager.setExact(AlarmManager.RTC_WAKEUP, timeinMilli, pendingIntent);
        }
    }
}

person pat8719    schedule 05.04.2019    source источник
comment
По той же причине я использую эту библиотеку с планировщиком заданий github.com/evernote/android-job   -  person madlymad    schedule 08.04.2019
comment
Это пример из учебника хорошо продуманного и сформулированного вопроса о переполнении стека.   -  person trixn    schedule 20.07.2021


Ответы (5)


Добавление флага намерения FLAG_RECEIVER_FOREGROUND

https://developer.android.com/reference/android/content/Intent#FLAG_RECEIVER_FOREGROUND перед вызовом широковещательного приемника должен помочь

Intent intent = new Intent(context, ScheduleAllReceiver.class);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
PendingIntent scheduleAllPendingIntent = PendingIntent.getBroadcast(context, SCHEDULER_DAILY_ALL, intent, PendingIntent.FLAG_UPDATE_CURRENT);
person Viraj Gaikwad    schedule 26.04.2019
comment
Не могли бы вы добавить какие-нибудь объяснения, почему это работает и почему мы должны это добавить? - person Vadim Kotov; 20.04.2020

Я столкнулся с подобными проблемами. Я пробовал с менеджером по работе, но результат был таким же. Когда телефон заблокирован и находится в спящем режиме, событие не запускается.

Но для срабатывания события в точное время вам нужно использовать только менеджер тревог. Он должен работать даже в спящем режиме.

Способ регистрации диспетчера будильников (используйте точное время вместо повторения)

public static void registerAlarm(Context context){
    final int FIVE_MINUTES_IN_MILLI = 300000;
    final int THIRTY_SECOND_IN_MILLI = 30000;
    long launchTime = System.currentTimeMillis() + FIVE_MINUTES_IN_MILLI;
    AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    Intent i = new Intent(context, BroadcastAlarmManger.class);
    PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
        am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, launchTime, pi);
    else am.setExact(AlarmManager.RTC_WAKEUP, launchTime, pi);
    Utility.printLog("timestamp "+launchTime);
}

Радиоприемник для будильника

public class BroadcastAlarmManger extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //register alarm again
         registerAlarm(context);
        .
        .
        .
        .
        //do your stuff    
    }
}

Декларация о манифесте

<receiver
        android:name="com.taxiemall.utility.BroadcastAlarmManger"
        android:enabled="true"
        android:exported="true"/>

Также вам придется вручную выполнить перезагрузку. После каждой перезагрузки зарегистрированные аварийные сигналы сбрасываются. Так что зарегистрируйте широковещательный приемник для перезагрузки Android и снова зарегистрируйте в нем свой будильник.

person abdul rehman    schedule 13.04.2019
comment
Он не работает в режиме ожидания, хотя это должно было быть указано в моем вопросе - person pat8719; 16.04.2019
comment
Взгляните на реализацию, которую я использую. Для меня он работает в дремлющем режиме. Спасибо - person abdul rehman; 16.04.2019
comment
+1 Таким образом, предоставленный вами код соответствует тому, что мы реализовали. Что мне не удалось включить в свой исходный вопрос, так это то, как я объявил своего получателя в декларации манифеста, он отличается от вашего, но я не уверен, имеет ли это значение. Есть идеи по этому поводу? - person pat8719; 16.04.2019
comment
Я думаю, что из-за большой задержки может быть, что Android не позволяет запускать событие. Я думаю, вам следует разделить мероприятие на несколько мероприятий. Например, если вам нужно запустить событие через 14 часов, попробуйте разделить его на 6-7 частей. Таким образом, вы активируете событие через 1-2 часа и снова зарегистрируете диспетчер сигналов тревоги на следующий час. Это может помочь, так как на короткий период событие запускается, как ожидалось. Я не уверен насчет этого, но вы можете попробовать. - person abdul rehman; 16.04.2019
comment
Привет, @ pat8719. Вы нашли решение? Я борюсь с этим. Не могли бы вы помочь мне включить пожарную сигнализацию и в спящем режиме? Спасибо. - person Chirag Prajapati; 16.03.2020
comment
@ChiragPrajapati, ты можешь объяснить свою проблему? - person abdul rehman; 19.03.2020
comment
@abdulrehman Могу ли я использовать службу Foreground, чтобы будильник работал даже в спящем режиме? - person Chirag Prajapati; 20.03.2020
comment
@ChiragPrajapati проверьте это сообщение pguardiola.com/blog/darealfragmentation-alarms и medium.com/mindorks/ - person abdul rehman; 31.03.2020
comment
@NarendraSingh, вы можете попросить пользователя добавить приложение в список желаний. Таким образом, это должно работать. Доступен код, чтобы попросить пользователя добавить ваше приложение в список желаний. - person abdul rehman; 28.04.2020

Да, ты прав. Теперь Google рекомендует использовать WorkManager вместо AlarmManager. В работе AlarmManager много ограничений. Дополнительную информацию можно найти здесь (режим ожидания)
Кроме того, у пиксельного телефона есть ошибка с alarmManager.

person Alexander    schedule 13.04.2019
comment
Полезно знать о потенциальной ошибке Oreo в пикселях, но это произошло в ОС, отличных от Oreo, а также на устройствах, отличных от Pixel. - person pat8719; 16.04.2019
comment
WorkManager может быть хорошей заменой для некоторых задач, но он не подходит для планирования работы, которая должна выполняться в точное время. В таких случаях по-прежнему рекомендуется AlarmManager. - person trixn; 20.07.2021
comment
@trixn проверяет уведомление developer.android.com/reference/android/app/AlarmManager Он не работает точно выше 19 API. Кроме того, WorkManager - это оболочка для аварийных сигналов, fifebaseService и т. д. - person Alexander; 20.07.2021
comment
@Alexander Конечно, если потребуется. Вам просто нужно использовать setExact или setWindow, если вам требуется точное выполнение. Это буквально второе предложение в примечании. И WorkManager - это не Wrapper по тревоге. Источник для этого утверждения? - person trixn; 20.07.2021

Это библиотека, которая у меня сработала.

person RSauther    schedule 16.04.2019
comment
Ответы только по ссылкам считаются очень низкокачественными. Не могли бы вы добавить некоторые подробности о том, почему следует использовать библиотеку? - person trixn; 20.07.2021

Вы не сможете долго запускать фоновые службы в Oreo, так как есть изменения в поведении, теперь Oreo для оптимизации системной памяти, батареи и т.д., он убивает фоновую службу, чтобы решить вашу проблему, вам следует использовать службу переднего плана.

Ознакомьтесь с ограничениями фонового выполнения https://developer.android.com/about/versions/oreo/android-8.0-changes

Предложение от меня, если вы можете использовать FCM, сделайте это, потому что приложения, такие как WeChat, Facebook используют его для доставки уведомлений, и у них нет никаких проблем ...

Надеюсь, это поможет разобраться в проблеме ....

person Abdul Aziz    schedule 14.04.2019
comment
мы не используем сервисы, мы используем alarmManager и ожидающие намерения. Ограничения на выполнение в фоновом режиме не должны применяться. Также, как упоминалось в вопросе, мы не используем Firebase, потому что мы пытаемся вызвать уведомление внутри, даже если нет подключения к Интернету. Кроме того, нам нужно будет создать отдельное событие firebase для каждого пользователя, которое может потребоваться для внесения больших изменений в инфраструктуру. Это кажется плохой идеей для проблемы, которая кажется, что этого не должно происходить. - person pat8719; 16.04.2019