AlarmManager не працює на кількох пристроях


85

У моїй програмі використовується AlarmManager, і вона працює з 4 років тому. Але я помітив, що на деяких пристроях він почав виходити з ладу.

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

Наприклад, пристрої Huawei мають своєрідний диспетчер батареї, який вбиває програми, і коли програму вбивають, заплановані будильники скасовуються. Отже, встановлення програми як "захищеної" в менеджері батарей Huawei вирішує проблему.

Але нещодавно я помітив, що це не працює з більшою кількістю пристроїв: Xiaomi, Samsung (можливо, це пов’язано з новим «розумним менеджером»?) ... Здається, така поведінка стає стандартною: вбивати фонові програми.

Хто-небудь щось про це знає? Будь-яким способом забезпечити спрацьовування тривоги?

РЕДАГУВАТИ: Цю проблему спричиняють "заставки", додані різними виробниками. Більше інформації тут: https://dontkillmyapp.com/


8
Виробники звинувачують додатки в енергоспоживанні, і вони продовжують продавати Octa-ядра, які споживають більше батареї в порівнянні з центральним процесором з меншою кількістю ядер. Чи думають вони, що просто додавання ядра пришвидшить їхні телефони?
FrozenFire

1
@AviLevinshtein Можливо, я неправильно зрозумів ваше запитання. Я створюю будильники у своїй діяльності. Потім, коли спрацьовує будильник, виконується трансляційний приймач і, нарешті, виконується WakefulIntentService (клас від @commonsware).
Sergio Viudes

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. Вони іноді вбивають фоновий процес та сигналізацію, щоб заощадити заряд акумулятора.
Анді Сусіло

1
У мене телефон huawei, зміна назви пакета на будильник / календар нічого не робить. Єдиний спосіб обійти це, додавши свою програму до списку захищених програм від менеджера телефонів
Ashish Pardhiye

9

Проблема полягає в Smart Manager. Samsung має менеджер акумуляторів, який часом відключає роботу певних програм у фоновому режимі. Він намагався "відновити" при поверненні до програми, але повністю вимикає програму або може відновити кожні 5 хвилин або близько того (залежно від того, як це має Samsung).

Це може працювати на біржових версіях Android, оскільки немає менеджера Samsung. Ви також можете встановити власну версію android, яка має деякі функції для включення SM (залежно від rom).


Я божеволію, бо у мене немає пристрою Samsung, щоб його перевірити. Я знаю лише те, що говорять мені користувачі мого додатка. Чи знаєте ви, чи проблема в тому, що AlarmManager не працює, оскільки додаток вбивається? Або проблема в тому, що пристрій не може прокинутися, коли спрацьовує будильник через цього менеджера?
Серхіо Віудес,

@SergioViudes Останнім часом багато компаній впроваджують власні. Такі, як LG, має таку, яка працює подібно до Samsung, можливо, у вашого телефону вона є? Проблема не в сигналізації, додаток будильника переведено в стан, коли він повністю неактивний. Smart Manager вважає, що це просто випадковий додаток, який вам не потрібен. Я помітив, що деякі програми можуть пройти через це, можливо, деякі програми приймаються розумним менеджером.
SA

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

Дякую Тім. Було б чудово вирішити цю проблему без необхідності виключати програми з "розумного" менеджера.
Sergio Viudes

такі пристрої, як xiaomi (miui), vivo та htc, за замовчуванням встановлюють цілу купу дозволів як помилкові, за винятком випадків, коли це додаток у списку "довірених" програм, які вони, здається, визначають самі (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 - найкраще рішення, але, на жаль, не дасть точних термінів.
Том,

1

У мене також є програма, яка встановлює будильники. Рішення полягає у використанні AlarmManager.setAlarmClock () на api> = 21. На це не впливає doze afaik і має додатковий бонус, якщо помістити піктограму будильника в системний трей.


Дякую за вашу відповідь. Чи є спосіб зняти піктограму будильника?
Sergio Viudes

На жаль, setAlarmClock іноді не працює. Я протестував його на пристрої Oreo з малою пам’яттю.
Борис Салімов

0

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

Думаю, вам потрібно вказати застереження чи відповіді на відповіді у списку додатків / магазинів Play, в якому зазначається, що для належної роботи цей додаток повинен бути включений у виняток із програми керування зарядом акумулятора.


Це повинен бути інший спосіб ... Користувачі не будуть читати застереження. Я не можу подумати, що телефони Samsung не дозволяють програмам використовувати AlarmManager ...
Серхіо Віудес

Тривоги не спрацьовує «на час», але вони будуть eventuially
Gavriel

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

0

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

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

так .. це біль .. але робота виконується БЕЗ ВАЖЛИВОСТІ ЩО


3
Дякуємо за вашу пропозицію, але я хотів би уникнути такого підходу, оскільки використання AlarmManager не споживає оперативної пам’яті та ресурсів. І, якщо ваш додаток буде вбито, служба зупиниться, так?
Серхіо Віудес,

я не сказав, що такий підхід є BOOLETPROOF, але принаймні він складається з різних версій api :)
ymz

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

я здогадуюсь що ви маєте рацію щодо цього .. єдине питання: що було б найгірше - ненадійний код чи погана робота? у всякому разі, я особисто вважаю , що є альтернативні способи блокування , які можуть бути придатні в деяких випадках (наприклад: stackoverflow.com/questions/5346694 / ... )
ЯМЗ

0

Ви слухаєте BOOT_COMPLETED? Потрібно встановити будильники знову, коли пристрій перезавантажується.


Так. Як я вже говорив, сигналізація працювала з 2012 року і дотепер. Коли пристрій перезавантажується, я перепланую будильники у BOOT_COMPLETED широкомовному приймачі.
Sergio Viudes

1
Потребувати перезавантаження для того, щоб ваш додаток знову працював, навіть не половина рішення
Тім,

1
@TimCastelijns, це зовсім не те, про що я кажу. ЯКЩО пристрій перезавантажено, усі будильники, встановлені за допомогою диспетчера сигналів, повинні бути встановлені знову.
Тайлер Пфафф,

@TylerPfaff так, але перезапуск пристрою не пов'язаний з проблемою у цьому питанні
Тім,

0

На якій версії Android працюють ці пристрої?

Починаючи з API 23, сама ОС перейде в режим очікування з низьким енергоспоживанням, коли вона деякий час не використовується, і в цьому режимі сигнали тривоги не подаватимуться. Однак програми можуть прямо сказати "Мені потрібно, щоб цей будильник спрацював у цей час, незалежно від використання акумулятора"; нові методи AlarmManager викликали setAndAllowWhileIdle()та setExactAndAllowWhileIdle().

З вашого опису виглядає так, що це може бути не конкретною причиною ваших проблем на пристроях певних виробників, але це те, про що повинні знати всі розробники, які використовують Менеджер тривог.

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


На пристроях Samsung із Smart Manager працює Lollipop. Я вже використовую setExactAndAllowWhileIdle для пристроїв Marshmallow. Я загляну до JobScheduler та GCM. У будь-якому випадку, я не знаю, чи проблема в тому, що будильник не спрацює, чи цей пристрій не пробудиться, коли спрацює будильник.
Sergio Viudes

0

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

Це лише тоді, коли ви "примусово зупините" або вимкнете програму, ви не отримаєте зворотних дзвінків від менеджера будильників.

Першопричиною може бути щось інше.

Також на M ... setExactAndAllowWhileIdle робить дроселювання ... тобто якщо ви плануєте будильник кожні 2 хвилини, він не спрацьовує. ..Вікно повинно бути 15 хвилин. .


1
Дякую за вашу відповідь. Але якщо ні, то чому додаток працює ідеально, коли в «Smart Manager» вимкнено «оптимізацію акумулятора»?
Sergio Viudes

ви запускаєте програму на корінному пристрої .. якщо так, менеджер додатків може також вимкнути програму ..
rupesh Jain

Ні, я не запускаю його на корінному пристрої.
Sergio Viudes

@rupeshjain "тобто якщо ви плануєте будильник кожні 2 хвилини, він не спрацьовує. ..Треба бути вікно 15 хв." це не зовсім так, це справжня проблема, якби це було правдою. Ви можете точно прочитати, який обмеження часу для планування в Документах Android для методу setExactAndAllowWhileIdle. Існують обмеження щодо того, як часто ці будильники спрацьовуватимуть для певної програми. За нормальної роботи системи вона не надсилатиме тривоги більше, ніж приблизно кожну хвилину, коли в режимах очікування з низьким енергоспоживанням ця тривалість може бути значно більшою за 15 хвилин.
eyadMhanna

0

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


0

Нам потрібно ввімкнути наш додаток в менеджері автозапуску в диспетчері програм, деякі телефони, такі як vivo v5,

In vivo v5, ми можемо дізнатися це меню в iManager -> Менеджер програм -> Автозапуск менеджера. Увімкніть наш додаток тут.

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


0

Я шукав відповідь і через кілька годин виявив:

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

У резюме можна дізнатись, чи не вбито вашу програму «Захищені програми», і це працює лише на пристроях Huawei. дайте мені знати, чи є рішення для інших пристроїв (Samsung, Sony, Xiaomi тощо).


0

Це може бути пізно, але я сподіваюся, це допоможе комусь.

Я так довго застряг у тій же проблемі. Але тепер я знаю, як вирішити цю проблему. Це для тих, хто може мати таку ж проблему. Люди постійно повторюють, що ви повинні ввімкнути автозапуск, але мені вдалося це зробити, не використовуючи автоматичний запуск.

Перш за все, 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.