AlarmManager не работает на нескольких устройствах


85

Мое приложение использует AlarmManager и работает 4 года назад. Но заметил, что на некоторых устройствах он начал глючить.

Я почти уверен, что код правильный (я использую WakefulBroadcastReceiver и setExactAndAllowWhileIdle для устройств с Doze), потому что он отлично работает на устройствах Nexus, но не работает на устройствах некоторых производителей (Huawei, Xiaomi ...).

Например, в устройствах Huawei есть своего рода диспетчер батареи, который убивает приложения, а когда приложение прекращается, запланированные будильники отменяются. Таким образом, установка приложения в качестве «защищенного» в диспетчере батарей Huawei решает проблему.

Но недавно я заметил, что он не работает с другими устройствами: Xiaomi, Samsung (может быть, это связано с новым «Умным менеджером»?) ... Похоже, такое поведение становится стандартом: убивать фоновые приложения.

Кто-нибудь знает что-нибудь об этом? Есть ли способ обеспечить срабатывание сигнализации?

РЕДАКТИРОВАТЬ: эта проблема вызвана «экономичными батареями», добавленными разными производителями. Подробнее здесь: https://dontkillmyapp.com/


8
Производители винят приложения в энергопотреблении и продолжают продавать восьмиядерные процессоры, которые потребляют больше батареи по сравнению с процессорами с меньшим количеством ядер. Думают ли они, что простое добавление ядра ускорит работу их телефонов?
FrozenFire

1
@AviLevinshtein Может, я неправильно понял ваш вопрос. Я создаю будильники в своей деятельности. Затем, когда срабатывает сигнал тревоги, запускается широковещательный приемник и, наконец, выполняется WakefulIntentService (класс из @commonsware).
Серхио Виудес

2
@JFValdes Я все еще ищу решение. AlarmManager отлично работает на устройствах с Vanilla Android. Проблема в том, что производители пытаются «улучшить» функции Android, и они сломали AlarmManager ... Производители не должны внедрять свои собственные «средства экономии заряда батареи», если они используют стандартный режим Doze, то AlarmManager будет работать отлично ... для решения ...
Серджио Виудес

1
Есть ли решение? Как другие приложения, такие как напоминания или что-то в этом роде, делают это? Должен быть другой вариант, кроме setAlarm, который предназначен для сигналов тревоги, а не для напоминаний
kv1dr

1
@SergioViudes Я также столкнулся с той же проблемой с устройствами Xiomi для отслеживания. и если я не позволю своему приложению ограничить экономию заряда батареи, то оно будет правильно работать на 3 из 4 устройств, выполнив следующие настройки - -> Перейти к батарее -> Питание -> Экономия заряда батареи -> ваше приложение Теперь выберите Без ограничений (для фоновых настроек), затем Разрешить вариант для фонового местоположения
Имран Хан Сайфи

Ответы:


17

Уже несколько недель пытаюсь решить. Ничего не нашел. Huawei просто убьет все тревоги через какое-то время. Если я помещаю приложение в защищенное приложение в режиме экономии заряда батареи, это не помогает. Но если я изменю имя пакета своего приложения, чтобы оно содержало такие слова, как будильник, часы или календарь, оно будет работать совершенно нормально, как на любых других устройствах. Я не понимаю, как Google может давать сертификаты на эту хрень. Я считаю, что OEM не должен модифицировать базовую платформу таким образом. Я понимаю, что у них есть собственная заставка, которая убивает приложение через некоторое время, когда пользователь его не использует. Но это убивает тревогу и защищенных приложений.

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

Обновление: защита по ключевым словам имени пакета уже не работает на текущих устройствах Huawei, это было верно в 2017 году.


Так же, как и я, я тоже пробую, но не могу решить эту проблему на некоторых брендах Xiaomi, Oppo, Huawei. Иногда они убивают фоновый процесс и тревогу для экономии заряда батареи.
Andi

1
У меня телефон huawei, изменение имени пакета на будильник / календарь ничего не дает. Единственный способ обойти это - добавить свое приложение в список защищенных приложений из диспетчера телефона
Ашиш Пардхие,

9

Проблема в Smart Manager. У Samsung есть диспетчер батареи, который иногда отключает работу определенных приложений в фоновом режиме. Он пытался «возобновить» при возврате в приложение, но полностью отключает приложение или может возобновлять работу каждые 5 минут или около того (в зависимости от того, как у Samsung).

Это будет работать на стандартных версиях Android, так как Samsung Manager отсутствует. Вы также можете установить специальную версию Android, в которой есть некоторые функции для включения SM (в зависимости от ROM).


Я схожу с ума, потому что у меня нет устройства Samsung, чтобы проверить это. Я знаю только то, что мне говорят пользователи моего приложения. Знаете ли вы, что проблема в том, что AlarmManager не работает из-за того, что приложение было убито? Или проблема в том, что устройство не может проснуться при срабатывании будильника из-за этого менеджера?
Серхио Виудес

@SergioViudes В последнее время многие компании внедряют свои собственные. Например, у LG есть тот, который работает аналогично Samsung, может быть, у вашего телефона он есть? Проблема не в будильнике, приложение будильника переведено в состояние, когда оно полностью неактивно. Smart Manager считает, что это просто случайное приложение, которое вам не нужно. Я заметил, что некоторые приложения могут пройти через это, возможно, некоторые приложения принимаются умным менеджером.
SA

1
@SergioViudes У меня есть самсунг, который нужно протестировать, и я могу сказать, что от него мало что можно получить. Когда умный менеджер оптимизирует ваше приложение, не возникает никаких ошибок или чего-то еще, оно просто умирает, как при принудительной остановке. Тем не менее, оно все еще в списке последних приложений
Тим,

Спасибо, Тим. Было бы здорово решить эту проблему, не исключая приложения из «Умного» Менеджера.
Серхио Виудес,

такие устройства, как xiaomi (miui), vivo и htc, по умолчанию устанавливают целый ряд разрешений как false, если только это не приложение в списке "доверенных" приложений, которое они сами определяют (whatsapp, truecaller и т. д. по умолчанию доверяют) ). Это становится кошмаром для программистов
desidigitalnomad

3

Большинство современных Android-устройств поставляются с приложением или механизмом, который автоматически пытается выяснить, как сэкономить заряд батареи, и в результате может убить некоторые сторонние приложения. Это может привести к удалению запланированных задач и заданий (например, не срабатывают будильники, не работают push-уведомления и т. Д.). Во многих случаях это происходит совершенно независимо от механизмов экономии заряда батареи Android, в моем случае я не мог больше оптимизировать батарею, когда обнаруживаю какую-то модель устройства, я перенаправляю пользователя в менеджер запуска, чтобы внести мое приложение в белый список

Вы нашли в этой ссылке для каждой модели намерение, которое вы должны вызвать https://android-arsenal.com/details/1/6771


2

Используйте AlarmManager для устройств <5.0 и JobScheduler для устройств 5.0+. Я не могу с уверенностью сказать, что на JobScheduler не повлияют махинации производителя, но мне это кажется гораздо менее вероятным, учитывая, что Android пытается переместить людей из AlarmManager в JobScheduler.

РЕДАКТИРОВАТЬ: Google представил собственное решение этой проблемы под названием WorkManager . Он абстрагирует несколько структур планирования и использует наиболее подходящую для устройства.


2
К сожалению, в отличие от класса AlarmManager, время использования JobScheduler не является точным. В моем приложении время должно быть точным :(
Серхио Виудес

Я попробовал, и некоторые оптимизаторы (по крайней мере, Samsung) убивают все ожидающие задачи в JobScheduler, когда экран гаснет. Так что это тоже сломано. Это происходит на 5.0. После обновления до 6.0 он работает нормально, я думаю, они это исправили. У других производителей пока не смог протестировать.
Sloy

Для точного определения времени вы не можете использовать фоновую службу или запланированную службу. Вы можете попробовать использовать службу переднего плана, но это создаст для пользователя постоянное уведомление (что, вероятно, нежелательно), а в некоторых телефонах есть встроенные средства устранения задач, которые автоматически уничтожат службу переднего плана. WorkManager - лучшее решение, но, к сожалению, не даст вам точного времени.
Tom

1

У меня также есть приложение, которое устанавливает будильники. Решение состоит в том, чтобы использовать AlarmManager.setAlarmClock () на api> = 21. Это не зависит от doze afaik и имеет дополнительный бонус в виде размещения значка будильника на панели задач.


Спасибо за Ваш ответ. Есть ли способ убрать иконку будильника?
Серхио Виудес

К сожалению, setAlarmClock иногда не работает. Я тестировал его на устройстве Oreo с малым объемом памяти.
Борис Салимов

0

в настоящее время большинство новых телефонов поставляются в комплекте с каким-либо менеджером по энергосбережению / батарее, который выполняет то же действие, что вы описали. не считая дубустеров и чистых мастеров.

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


Должен быть другой способ сделать это ... Пользователи не будут читать отказ от ответственности. Я не могу думать, что телефоны Samsung не позволяют приложениям использовать AlarmManager ...
Серхио Виудес

Сигнализация не сработает «вовремя», но в конечном итоге сработает
Гавриил

Я бы сказал (к сожалению) самый полезный ответ. Хотелось бы найти лучшее решение, но производители оборудования портят отлично работающий ванильный Android.
caw

0

я перестал использовать AlarmManager некоторое время назад ... лучшая и более стабильная альтернатива

  1. создать услугу
  2. зарегистрируйте BroadcastReceiver для BOOT_COMPLETED
  3. уволить службу из получателя
  4. запустите новый обработчик внутри своей службы, который зацикливается каждые X минут ( Android - периодический запуск метода с использованием вызова postDelayed () )
  5. проверьте, пришло ли время для выполнения задачи: сейчас - время выполнения> 0 ( Как найти продолжительность разницы между двумя датами в java? )
  6. если да .. выполнить задачу и остановить обработчик

да .. это боль .. но работа сделана НЕ ВАЖНО ЧТО


3
Спасибо за ваше предложение, но я бы хотел избежать этого подхода, потому что использование AlarmManager не потребляет оперативную память или какие-либо ресурсы. И если ваше приложение будет убито, служба остановится, верно?
Серхио Виудес

я не сказал, что этот подход БУЛЕТЗАЩИЩЕН, но, по крайней мере, он состоит из разных версий api :)
ymz

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

я думаю, что вы правы в этом .. единственный вопрос: что будет хуже - ненадежный код или плохая производительность? в любом случае, я лично думаю, что есть альтернативные способы блокировки, которые могут быть подходящими в некоторых случаях (например: stackoverflow.com/questions/5346694/… )
ymz

0

Вы слушаете BOOT_COMPLETED? Вам нужно снова установить будильник при перезагрузке устройства.


Да. Как я уже сказал, сигнализация работала с 2012 года по настоящее время. Когда устройство перезагружается, я переназначаю будильники в широковещательном приемнике BOOT_COMPLETED.
Серхио Виудес

1
Требование перезагрузки для того, чтобы ваше приложение снова работало, - это даже не половина решения,
Тим,

1
@TimCastelijns, я совсем не это говорю. ЕСЛИ устройство перезагружается, все тревоги, установленные с помощью диспетчера тревог, должны быть установлены заново.
Тайлер Пфафф

@TylerPfaff: да, но перезапуск устройства не имеет отношения к проблеме, рассматриваемой в этом вопросе,
Тим

0

Какая версия Android работает на этих устройствах?

Начиная с API 23, сама ОС переходит в режим ожидания с низким энергопотреблением, если она некоторое время не использовалась, и в этом режиме не будут доставляться сигналы тревоги. Однако есть способ для приложений явно сказать: «Мне нужно, чтобы этот будильник сработал в это время независимо от использования батареи»; новые методы AlarmManager называются setAndAllowWhileIdle()и setExactAndAllowWhileIdle().

Судя по вашему описанию, это не может быть конкретной причиной ваших проблем на устройствах некоторых OEM-производителей, но это то, о чем должны знать все разработчики, использующие Alarm Manager.

Наконец, многие случаи использования диспетчера аварийных сигналов лучше решаются с помощью механизмов планировщика заданий. Для обратной совместимости Play Services "GCM Network Manager" на самом деле очень близок к планировщику заданий по функциональности - он использует планировщик заданий внутри в новых версиях Android - и не обязательно связан с сетью, несмотря на название класса.


На устройствах Samsung с Smart Manager работает Lollipop. Я уже использую setExactAndAllowWhileIdle для устройств Marshmallow. Я посмотрю на JobScheduler и GCM. В любом случае, я не знаю, проблема в том, что будильник не срабатывает, или это устройство не просыпается при срабатывании будильника.
Серхио Виудес

0

Я не думаю, что удаление приложения помешает диспетчеру сигналов тревоги разбудить ваше приложение.

Только когда вы «принудительно останавливаете» или отключаете приложение, вы не получаете обратных звонков от диспетчера тревог.

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

Также на M ... setExactAndAllowWhileIdle дросселируется ... то есть, если вы планируете будильник каждые 2 минуты, он не сработает. .. Должно быть окно 15 минут. .


1
Спасибо за Ваш ответ. Но если нет, то почему приложение работает отлично, когда в Smart Manager отключена «оптимизация батареи»?
Серхио Виудес

Вы запускаете приложение на рутованном устройстве ... если да, менеджер приложений тоже может отключить приложение ...
rupesh jain

Нет, я не запускаю его на рутированном устройстве.
Серхио Виудес

@rupeshjain "то есть, если вы запланируете будильник каждые 2 минуты, он не сработает ... Должно быть окно 15 минут". это не совсем правда, это настоящая проблема, если это правда. Вы можете точно прочитать, какой срок для планирования в Android Docs для метода setExactAndAllowWhileIdle. Существуют ограничения на частоту срабатывания этих сигналов тревоги для конкретного приложения. При нормальной работе системы эти аварийные сигналы будут отправляться не чаще, чем примерно каждую минуту, в то время как в энергосберегающих режимах холостого хода эта продолжительность может быть значительно больше 15 минут.
eyadMhanna

0

Для Xiaomi вам может потребоваться включить AutoStart для вашего приложения. Я пытаюсь внести изменения в список модификаций Android (обычно от производителя телефона), которые могут повлиять на фоновый процесс. Если у вас есть что-то новенькое, пожалуйста, добавьте сюда ответ. Список средств убийства Android.


0

Нам нужно включить наше приложение в диспетчере автозапуска в диспетчере приложений, на некоторых телефонах, таких как vivo v5,

В vivo v5 это меню можно найти в iManager -> Диспетчер приложений -> Диспетчер автозапуска. Включите наше приложение здесь.

Тогда ваш будильник / менеджер будильника вызовет тревогу, если приложение будет убито или закрыто.


0

Я искал ответ и через несколько часов нашел вот что:

https://stackoverflow.com/a/35220476/3174791

В резюме есть способ узнать, было ли ваше приложение убито «Защищенными приложениями», и это работает только на устройствах Huawei. дайте мне знать, есть ли какое-либо решение для других устройств (Samsung, Sony, Xiaomi и т. д.).


0

Это может быть поздно, но я надеюсь, что это кому-то поможет.

Я так долго зацикливался на одной и той же проблеме. Но теперь я знаю, как решить эту проблему. Это для всех, у кого может быть такая же проблема. Люди продолжают говорить, что вы должны включить AutoStart, но мне удалось это сделать без использования автоматического запуска.

Во-первых, WakeFullBroadcastaReceiver устарел, и вам следует использовать BroadcastReceiver. Во-вторых, вы должны использовать ForegroudService вместо BackgroundService.

Я дам вам следующий пример:

IntentService.class

public class NotificationService extends IntentService {


//In order to send notification when the app is close
//we use a foreground service, background service doesn't do the work.



public NotificationService() {
    super("NotificationService");
}

@Override
public void onCreate() {
    super.onCreate();

}

@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
    super.onStartCommand(intent, flags, startId);

    //There is no difference in the result between start_sticky or start_not_sticky at the moment
    return START_NOT_STICKY;
}

@Override
protected void onHandleIntent(@Nullable Intent intent) {

    //TODO check if the app is in foreground or not, we can use activity lifecyclecallbacks for this

    startForegroundServiceT();
    sendNotification(intent);
    stopSelf();
}


/***
 * you have to show the notification to the user when running foreground service
 * otherwise it will throw an exception
 */
private void startForegroundServiceT(){

    if (Build.VERSION.SDK_INT >= 26) {
        String CHANNEL_ID = "my_channel_01";
        NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
                "Channel human readable title",
                NotificationManager.IMPORTANCE_DEFAULT);

        ((NotificationManager) 
   getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);

        Notification notification = new Notification.Builder(this, CHANNEL_ID)
                .setContentTitle("")
                .setContentText("").build();

        startForeground(1, notification);
    }
}

private void sendNotification(Intent intent){

    //Send notification
    //Use notification channle for android O+
}
}

запустить службу переднего плана в BroadcastReceiver.class

public class AlarmReceiver extends BroadcastReceiver {


@Override
public void onReceive(Context context, Intent intent) {


    Intent service = new Intent(context, NotificationService.class);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        context.startForegroundService(service);
    } else {
        context.startService(service);
    }

}
}

А вот setAlarms такой:

 public static void setAlarm(Context context, int requestCode, int hour, int minute){


    AlarmManager alarmManager =( AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(context//same activity should be used when canceling the alarm
            , AlarmReceiver.class);
    intent.setAction("android.intent.action.NOTIFY");

    //setting FLAG_CANCEL_CURRENT makes some problems. and doest allow the cancelAlarm to work properly
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1001, intent, 0);

    Calendar time = getTime(hour, minute);

    //set Alarm for different API levels
    if (Build.VERSION.SDK_INT >= 23){
        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,time.getTimeInMillis(),pendingIntent);
    }
    else{
        alarmManager.set(AlarmManager.RTC_WAKEUP,time.getTimeInMillis(),pendingIntent);
    }

Затем вы должны объявить получателя и службу переднего плана в манифесте.

       <receiver android:name=".AlarmReceiver"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.NOTIFY">

            </action>
        </intent-filter>
    </receiver>
    <service
        android:name=".NotificationService"
        android:enabled="true"
        android:exported="true"></service>

Я надеюсь, что это помогает кому-то.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.