Moja aplikacja korzysta z AlarmManagera i działa od 4 lat. Ale zauważyłem, że zaczęło zawodzić w niektórych urządzeniach.
Jestem prawie pewien, że kod jest poprawny (używam WakefulBroadcastReceiver i setExactAndAllowWhileIdle dla urządzeń z funkcją Doze), ponieważ działa idealnie na urządzeniach Nexus, ale zawodzi na urządzeniach niektórych producentów (Huawei, Xiaomi ...).
Na przykład urządzenia Huawei mają pewnego rodzaju menedżera baterii, który zabija aplikacje, a kiedy aplikacja zostaje zabita, zaplanowane alarmy są anulowane. Ustawienie aplikacji jako „chronionej” w menedżerze baterii Huawei rozwiązuje problem.
Ale ostatnio zauważyłem, że nie działa z większą liczbą urządzeń: Xiaomi, Samsung (może ma to związek z nowym „Smart Managerem”?) ... Wygląda na to, że takie zachowanie staje się standardem: zabijanie aplikacji działających w tle.
Ktoś wie coś na ten temat? Czy jest jakiś sposób, aby zapewnić uruchomienie alarmu?
EDYCJA: Ten problem jest spowodowany przez „oszczędzanie baterii” dodawane przez różnych producentów. Więcej informacji tutaj: https://dontkillmyapp.com/
źródło
Odpowiedzi:
Już od kilku tygodni próbuję go rozwiązać. Nic nie znalazłem. Huawei po pewnym czasie po prostu wyłącza wszystkie alarmy. Jeśli umieszczę aplikację w chronionej aplikacji w oszczędzaniu baterii, to nie pomoże. Ale jeśli zmienię nazwę pakietu mojej aplikacji, aby zawierała słowa takie jak alarm, zegar lub kalendarz, działa to całkowicie normalnie, jak na każdym innym urządzeniu. Nie rozumiem, jak Google może wystawić certyfikat za to gówno. Uważam, że OEM nie powinien w taki sposób modyfikować podstawowej platformy. Rozumiem, że mają własny program do oszczędzania ciasta, który po pewnym czasie zabija aplikację, gdy użytkownik jej nie używa. Ale to zabijanie alarmów również chronionych aplikacji.
Pomocna jest również funkcja setAlarmClock () dla dokładnego czasu alarmów. Ale nie jest możliwe użycie tego do myśli takich jak aktualizacja widżetów.
Aktualizacja: Ochrona za pomocą słów kluczowych nazw pakietów już nie działa na obecnych urządzeniach Huawei, tak było w 2017 roku.
źródło
Problemem jest Smart Manager. Samsung ma menedżera baterii, który czasami wyłącza działanie niektórych aplikacji w tle. Próbował „wznowić” po powrocie do aplikacji, ale całkowicie ją wyłącza lub może wznawiać się co około 5 minut (w zależności od tego, jak ma to Samsung).
To działałoby na standardowych wersjach Androida, ponieważ nie ma Samsung Manager. Możesz także zainstalować niestandardową wersję Androida, która ma pewne funkcje umożliwiające obsługę SM (w zależności od romu).
źródło
Większość nowoczesnych urządzeń z Androidem jest wyposażona w aplikację lub mechanizm, który automagicznie próbuje dowiedzieć się, jak oszczędzać baterię, aw rezultacie może zabić niektóre aplikacje innych firm. Może to spowodować usunięcie zaplanowanych zadań i zadań (np. Nie włączają się alarmy, nie działają powiadomienia push itp.). W wielu przypadkach dzieje się to całkowicie niezależnie od mechanizmów oszczędzania baterii w Androidzie, w moim przypadku nie mogłem dokonać większej optymalizacji baterii po wykryciu modelu jakiegoś urządzenia, przekierowuję użytkownika do menadżera uruchamiania, aby dodać moją aplikację do białej listy
W tym linku dla każdego modelu znalazłeś zamiar wywołania https://android-arsenal.com/details/1/6771
źródło
Użyj AlarmManager dla urządzeń <5.0 i JobScheduler dla urządzeń 5.0+. Nie mogę powiedzieć na pewno, że na JobScheduler nie wpłyną oszustwa producentów, ale wydaje mi się to znacznie mniej prawdopodobne, biorąc pod uwagę, że Android próbuje przenieść ludzi z AlarmManager do JobScheduler.
EDYCJA: Google opracowało własne rozwiązanie tego problemu o nazwie WorkManager . Oddziela wiele ram planowania i używa najbardziej odpowiedniego dla urządzenia.
źródło
Mam też aplikację, która ustawia alarmy. Rozwiązaniem jest użycie AlarmManager.setAlarmClock () na api> = 21. Nie ma na to wpływu drzemka afaik i ma dodatkową zaletę polegającą na umieszczeniu ikony budzika w zasobniku systemowym.
źródło
większość nowych telefonów jest obecnie wyposażona w pewnego rodzaju menedżera oszczędzania baterii / energii, który robi to samo, co opisałeś. nie licząc duboosterów i czystych mistrzów.
Myślę, że musisz umieścić zrzeczenie się lub często zadawane pytania na liście aplikacji / Sklepu Play, stwierdzając, że ta aplikacja musi zostać umieszczona z wyjątkiem aplikacji do zarządzania baterią, aby działała poprawnie.
źródło
przestałem używać AlarmManager jakiś czas temu ... lepsza i stabilniejsza alternatywa
tak .. to jest uciążliwe .. ale praca jest wykonana NIEZALEŻNIE OD CO
źródło
Czy słuchasz BOOT_COMPLETED? Musisz ponownie ustawić alarmy po ponownym uruchomieniu urządzenia.
źródło
W jakiej wersji Androida działają te urządzenia?
Począwszy od API 23, sam system operacyjny przejdzie w tryb bezczynności o niskim poborze mocy, gdy nie będzie używany przez jakiś czas, iw tym trybie alarmy nie będą dostarczane. Istnieje jednak sposób, aby aplikacje wyraźnie powiedziały: „Chcę, aby ten alarm włączył się w tym momencie, niezależnie od zużycia baterii”; nowe metody AlarmManager o nazwie
setAndAllowWhileIdle()
isetExactAndAllowWhileIdle()
.Z twojego opisu wynika, że może to nie być konkretną przyczyną twoich problemów na niektórych urządzeniach OEM, ale jest to coś, o czym wszyscy programiści używający Menedżera alarmów powinni być świadomi.
Wreszcie, wiele zastosowań Menedżera alarmów można lepiej rozwiązać za pomocą mechanizmów Harmonogramu zadań. Ze względu na kompatybilność wsteczną „Menedżer sieci GCM” usług Play jest w rzeczywistości bardzo zbliżony funkcjonalnie do Harmonogramu zadań - korzysta z tego narzędzia wewnętrznie w nowszych wersjach systemu Android - i nie zawsze dotyczy sieci, pomimo nazwy klasy.
źródło
Nie sądzę, aby zabicie aplikacji uniemożliwiło menedżerowi alarmów obudzenie aplikacji.
Tylko wtedy, gdy „wymusisz zatrzymanie” lub wyłączysz aplikację, nie otrzymasz oddzwonień od menedżera alarmów.
Przyczyną może być coś innego.
Również w M ... setExactAndAllowWhileIdle ogranicza przepustowość ... to znaczy, jeśli zaplanujesz alarm co 2 minuty, nie zostanie on wyzwolony. ..Musi być 15-minutowe okno. .
źródło
W przypadku Xiaomi może być konieczne włączenie funkcji AutoStart dla aplikacji. Próbuję zrobić listę modyfikacji Androida (zwykle od producenta telefonu), które mogą wpływać na proces w tle. Jeśli masz coś nowego, dodaj odpowiedź tutaj Lista zabójców zadań Androida
źródło
Musimy włączyć naszą aplikację w menedżerze autostartu w menedżerze aplikacji, niektóre telefony, takie jak vivo v5,
In vivo v5 menu to znajdziemy w iManager -> App Manager -> Auto Start Manager. Włącz naszą aplikację tutaj.
Następnie twój menedżer alarmów / alarmów uruchomi alarm, jeśli aplikacja zostanie zabita lub zamknięta.
źródło
Szukałem odpowiedzi i po kilku godzinach znalazłem to:
https://stackoverflow.com/a/35220476/3174791
W wznowieniu można dowiedzieć się, czy Twoja aplikacja została zabita przez „Chronione aplikacje” i działa to tylko na urządzeniach Huawei. daj mi znać, jeśli jest jakieś rozwiązanie dla innych urządzeń (Samsung, Sony, Xiaomi itp.).
źródło
To może być późno, ale mam nadzieję, że to komuś pomoże.
Tak długo tkwiłem w tym samym problemie. Ale teraz wiem, jak rozwiązać ten problem. To jest dla każdego, kto może mieć ten sam problem. Ludzie ciągle mówią, że musisz włączyć AutoStart, ale udało mi się to bez użycia automatycznego startu.
Po pierwsze, WakeFullBroadcastaReceiver jest teraz przestarzały i powinieneś używać BroadcastReceiver. Po drugie, musisz użyć ForegroudService zamiast BackgroundService.
Poniżej podam przykład:
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+ } }
uruchom usługę pierwszoplanową w 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); } } }
A setAlarmy takie jak ten:
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); }
Następnie musisz zadeklarować odbiorcę i usługę pierwszoplanową w manifeście.
<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>
Mam nadzieję, że to komuś pomoże.
źródło