Как использовать Android AlarmManager с небольшими интервалами, например, 1 минута?

Я хочу сделать внешний служебный монитор и получать уведомления о проблемах как можно быстрее.

Я пытался настроить AlarmManager с интервалом 1-2 минуты, но похоже, что он срабатывает случайным образом каждые несколько минут.

Конечно, я хочу быть в безопасности, чтобы не убить мою фоновую задачу Android, которая перестанет отслеживать, если я просто использую Service.

Можно ли использовать AlarmManager небольшими точными интервалами?

Какие подходы используются в таких приложениях, как Facebook, Gmail, для уведомления о новых сообщениях?

Не лучше ли сделать Service с startForeground и частичным WakeLock?


person Piotr Müller    schedule 17.06.2014    source источник


Ответы (3)


Я попытался настроить AlarmManager с интервалом 1-2 минуты, но похоже, что он срабатывает случайным образом каждые несколько минут.

Поскольку вы решили не показывать, как вы «настраиваете AlarmManager с интервалом 1-2 минуты», вам будет сложно помочь. Прочтите документацию для AlarmManager и обратите внимание на неточное поведение по умолчанию, новое для Android 4.4.

Я хочу быть в безопасности, чтобы не убить мою фоновую задачу Android, которая перестанет отслеживать, если я просто использую Service.

AlarmManager не решает всех проблем в этом плане. Например, если пользователь решит принудительно остановить ваше приложение (например, через Настройки), ваши будильники будут удалены.

Можно ли использовать AlarmManager с небольшими точными интервалами?

Используйте setRepeating() на Android 1.0–4.3 и setExact() на Android 4.4+. С setExact(), как часть обработки одного тревожного события, вам нужно будет запланировать следующее тревожное событие.

Было бы лучше сделать Service с startForeground и частичным WakeLock?

Только если ваше устройство всегда подключено к источнику питания (например, монитор промышленных процессов).

person CommonsWare    schedule 17.06.2014
comment
Вам не нужно беспокоиться о 4.4 и более поздних версиях, если вы устанавливаете целевую версию ниже 4.4. - person Parth Kapoor; 17.06.2014
comment
@ Eu.Dr .: Правильно. Однако выбор targetSdkVersion зависит от многих факторов. Сообразительные программисты принимают во внимание, что когда-нибудь им нужно будет поднять targetSdkVersion и они забудут о влиянии этого на срабатывание сигнализации. Поэтому такие программисты выберут setExact() в момент разработки нового AlarmManager кода, когда необходимы точные сигналы тревоги. targetSdkVersion в основном предназначен для облегчения перехода для уже существующего кода, а не как лицензия на игнорирование изменений при написании нового кода. - person CommonsWare; 17.06.2014
comment
Приму это, но я не могу достичь 1-минутного интервала вообще, даже на целевом SDK adroid 3. Это может быть связано с тем, что я использую MIUI Android, похоже, есть какое-то внутреннее ограничение, равное ровно 5 минутам, как наименьший интервал срабатывания сигнализации. - person Piotr Müller; 18.06.2014
comment
@killer_PL: Я использовал AlarmManager для демонстрации, установленной на пять секунд, так что он определенно способен на это. Но AlarmManager - это область, в которой производители устройств вносят изменения, пытаясь продлить срок службы батареи, поэтому меня не удивит, если ваше устройство является источником вашей проблемы. Вы можете сравнить с эмулятором x86, или другим устройством, или чем-то еще. - person CommonsWare; 18.06.2014
comment
setRepeating() не работает надежно на Android 5 и более поздних версиях на некоторых устройствах, даже если вы установите targetSdk на 8 (Android 2.2). Большинство новых устройств, похоже, игнорируют targetSdk настройку для этого и используют свои собственные алгоритмы управления питанием. К несчастью. - person David Wasser; 17.11.2016

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

public class AlarmManagerBroadcastReceiver extends BroadcastReceiver  
{
private static final int _REFRESH_INTERVAL = 60 * 1; // 1 minutes
// Alarm id
    private static final int ALARM_ID = 102; // This can be any random integer.

    PendingIntent pi = null;
    AlarmManager am= null;

@Override
    public void onReceive(Context context, Intent intent) 
    {
        /* All actions to be handled here.. */
        }


    // This is to initialize the alarmmanager and the pending intent. It is done in separate method because, the same alarmmanager and
    // pending intent instance should be used for setting and cancelling the alarm.

    public void SetContext(Context context)
    {
        this.context = context;
        am=(AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(context, AlarmManagerBroadcastReceiver.class);
        pi = PendingIntent.getBroadcast(context, ALARM_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    }

    // Setting the alarm to call onRecieve every _REFRESH_INTERVAL seconds
    public void SetAlarm()
    {
        // am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * _REFRESH_INTERVAL , pi);
        try
        {
            am.cancel(pi);
        }catch (Exception ignored){}
        am.setRepeating(AlarmManager.RTC_WAKEUP, SystemClock.elapsedRealtime(), 1000 * _REFRESH_INTERVAL , pi);
    }

    // Cancel the alarm.
    public void CancelAlarm()
    {
        am.cancel(pi);
    }

}
person Nishanthi Grashia    schedule 17.06.2014
comment
Это решение такое же, как у меня, и срабатывает ровно каждые 5 минут. - person Piotr Müller; 17.06.2014
comment
Обратите внимание на два момента: 1) Начиная с API 19, все предупреждения неточны; 2) Чтобы это работало в течение длительного времени, широковещательный приемник должен быть зарегистрирован в манифесте, а не динамически. - person G. Blake Meike; 17.06.2014

person    schedule
comment
В моем случае это происходит ровно каждые 5 минут. - person Piotr Müller; 17.06.2014