Uwaga: Wypróbowałem różne rozwiązania, o których pisano tutaj na StackOverflow (przykład tutaj ). Nie zamykaj tego, nie sprawdzając, czy twoje rozwiązanie z tego, co znalazłeś, działa przy użyciu testu, który napisałem poniżej.
tło
W aplikacji jest wymagane, aby użytkownik ustawił przypomnienie, które ma być zaplanowane o określonej godzinie, więc gdy aplikacja zostanie uruchomiona w tym czasie, robi coś małego w tle (tylko niektóre operacje zapytania DB) i pokazuje proste powiadomienie, aby opowiedzieć o przypomnieniu.
W przeszłości korzystałem z prostego kodu, aby ustawić coś do zaplanowania we względnie określonym czasie:
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val pendingIntent = PendingIntent.getBroadcast(context, requestId, Intent(context, AlarmReceiver::class.java), PendingIntent.FLAG_UPDATE_CURRENT)
when {
VERSION.SDK_INT >= VERSION_CODES.KITKAT -> alarmManager.setExact(AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
else -> alarmManager.set(AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
}
class AlarmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log.d("AppLog", "AlarmReceiver onReceive")
//do something in the real app
}
}
Stosowanie:
val timeToTrigger = System.currentTimeMillis() + java.util.concurrent.TimeUnit.MINUTES.toMillis(1)
setAlarm(this, timeToTrigger, 1)
Problem
Testowałem teraz ten kod na emulatorach na nowych wersjach Androida i na Pixelu 4 z Androidem 10 i wydaje się, że nie uruchamia się, a może uruchamia się po bardzo długim czasie od czasu, gdy go dostarczam. Zdaję sobie sprawę z okropnego zachowania, które niektórzy producenci OEM dodali do usuwania aplikacji z ostatnich zadań, ale ten dotyczy zarówno emulatorów, jak i urządzenia Pixel 4 (w magazynie).
Przeczytałem o dokumentach dotyczących ustawiania alarmu, że został on ograniczony do aplikacji, aby nie pojawiał się zbyt często, ale to nie wyjaśnia, jak ustawić alarm w określonym czasie i nie wyjaśnia jak to się dzieje, że aplikacja Google Clock osiąga sukces?
Nie tylko to, ale zgodnie z tym, co rozumiem, mówi, że ograniczenia powinny być stosowane szczególnie w przypadku stanu niskiego poboru mocy urządzenia, ale w moim przypadku nie miałem tego stanu, zarówno na urządzeniu, jak i na emulatorach. Ustawiłem uruchamianie alarmów za około minutę.
Widząc, że wiele aplikacji budzika nie działa już tak, jak kiedyś, myślę, że czegoś brakuje w dokumentacji. Przykładem takich aplikacji jest popularna aplikacja Timely, która została kupiona przez Google, ale nigdy nie otrzymała nowych aktualizacji w celu obsługi nowych ograniczeń, a teraz użytkownicy chcą ją z powrotem. . Jednak niektóre popularne aplikacje działają dobrze, takie jak ta .
Co próbowałem
Aby sprawdzić, czy rzeczywiście działa alarm, wykonuję te testy, gdy próbuję wyzwolić alarm za minutę po zainstalowaniu aplikacji po raz pierwszy, wszystko po podłączeniu urządzenia do komputera (aby wyświetlić dzienniki):
- Testuj, gdy aplikacja jest na pierwszym planie, widoczna dla użytkownika. - zajęło 1-2 minuty.
- Sprawdź, kiedy aplikacja została wysłana w tło (na przykład za pomocą przycisku Home) - zajęło to około 1 minuty
- Sprawdź, kiedy zadanie aplikacji zostało usunięte z ostatnich zadań. - Czekałem ponad 20 minut i nie widziałem wyzwolenia alarmu, piszącego do dzienników.
- Jak # 3, ale także wyłącz ekran. Prawdopodobnie byłoby gorzej ...
Próbowałem użyć następnych rzeczy, wszystko nie działa:
alarmManager.setAlarmClock(AlarmManager.AlarmClockInfo(timeToTrigger, pendingIntent), pendingIntent)
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
połączenie któregokolwiek z powyższych, z:
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) alarmManager.setWindow(AlarmManager.RTC_WAKEUP, 0, 60 * 1000L, pendingIntent)
Próbowałem użyć usługi zamiast BroadcastReceiver. Wypróbowałem też inny proces.
Próbowałem zignorować aplikację z optymalizacji baterii (nie pomogło), ale ponieważ inne aplikacje jej nie potrzebują, ja też nie powinienem jej używać.
Próbowałem użyć tego:
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP)
alarmManager.setAlarmClock(AlarmManager.AlarmClockInfo(timeToTrigger, pendingIntent), pendingIntent)
AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
- Próbowałem mieć usługę, która będzie wyzwalana przez onTaskRemoved , aby ponownie ustawić tam alarm, ale to też nie pomogło (usługa działała dobrze).
Jeśli chodzi o aplikację Google Clock, nie widziałem w niej nic specjalnego poza tym, że wyświetla powiadomienie przed uruchomieniem, a także nie widzę go w sekcji „niezoptymalizowanej” ekranu ustawień optymalizacji baterii.
Widząc, że to wygląda na błąd, zgłosiłem to tutaj , w tym przykładowy projekt i wideo pokazujące problem.
Sprawdziłem wiele wersji emulatora i wygląda na to, że takie zachowanie zaczęło się od API 27 (Android 8.1 - Oreo). Patrząc na dokumenty , nie widzę wzmianki o AlarmManager, ale napisano o różnych pracach w tle.
Pytania
Jak ustawić coś, co ma być teraz uruchamiane we względnie dokładnym czasie?
Dlaczego powyższe rozwiązania już nie działają? Czy coś mi brakuje? Pozwolenie? Może powinienem zamiast tego użyć Robotnika? Ale czy to nie znaczy, że może wcale nie zadziałać na czas?
W jaki sposób aplikacja Google „Zegar” przezwycięża to wszystko i zawsze uruchamia się dokładnie o określonej godzinie, nawet jeśli została uruchomiona jeszcze minutę temu? Czy tylko dlatego, że jest to aplikacja systemowa? Co się stanie, jeśli zostanie zainstalowany jako aplikacja użytkownika na urządzeniu, które nie ma wbudowanej aplikacji?
Jeśli powiesz, że to dlatego, że jest to aplikacja systemowa, Znalazłem inną aplikację, która może wywołać alarm dwukrotnie w ciągu 2 minut, tutaj , choć myślę, że może skorzystać z usługi pierwszoplanowy czasami.
EDYCJA: utworzyłem małe repozytorium Github do przetestowania pomysłów tutaj .
EDYCJA: w końcu znalazłem próbkę, która jest zarówno otwarta, jak i nie ma tego problemu. Niestety jest to bardzo skomplikowane i wciąż próbuję dowiedzieć się, co czyni go tak różnym (i jaki jest minimalny kod, który powinienem dodać do mojego POC), który pozwala, aby jego alarmy pozostały zaplanowane po usunięciu aplikacji z ostatnich zadań