Hinweis: Ich habe verschiedene Lösungen ausprobiert, über die hier in StackOverflow geschrieben wurde (Beispiel hier ). Bitte schließen Sie dies nicht, ohne zu überprüfen, ob Ihre Lösung von dem, was Sie gefunden haben, mit dem unten beschriebenen Test funktioniert.
Hintergrund
Für die App ist es erforderlich, dass der Benutzer eine Erinnerung festlegt, die zu einem bestimmten Zeitpunkt geplant werden soll. Wenn die App zu diesem Zeitpunkt ausgelöst wird, führt sie im Hintergrund etwas Winziges aus (nur eine DB-Abfrageoperation) und zeigt a einfache Benachrichtigung, um über die Erinnerung zu erzählen.
In der Vergangenheit habe ich einen einfachen Code verwendet, um etwas festzulegen, das zu einem relativ bestimmten Zeitpunkt geplant werden soll:
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
}
}
Verwendungszweck:
val timeToTrigger = System.currentTimeMillis() + java.util.concurrent.TimeUnit.MINUTES.toMillis(1)
setAlarm(this, timeToTrigger, 1)
Das Problem
Ich habe diesen Code jetzt auf Emulatoren in neuen Android-Versionen und auf Pixel 4 mit Android 10 getestet, und er scheint nicht auszulösen, oder er wird möglicherweise nach einer sehr langen Zeit seit dem, was ich ihm zur Verfügung stelle, ausgelöst. Ich bin mir des schrecklichen Verhaltens bewusst , das einige OEMs zum Entfernen von Apps aus den letzten Aufgaben hinzugefügt haben, aber dieses ist sowohl auf Emulatoren als auch auf Pixel 4-Geräten (Standard).
Ich habe in den Dokumenten über das Einstellen eines Alarms gelesen , dass er für Apps eingeschränkt wurde, damit er nicht zu oft auftritt, aber dies erklärt nicht, wie ein Alarm zu einem bestimmten Zeitpunkt eingestellt wird, und es erklärt nicht Wie kommt es, dass Googles Clock-App erfolgreich ist?
Darüber hinaus heißt es nach meinem Verständnis, dass die Einschränkungen insbesondere für den Energiesparmodus des Geräts gelten sollten. In meinem Fall hatte ich diesen Status jedoch weder auf dem Gerät noch auf den Emulatoren. Ich habe die Alarme so eingestellt, dass sie in ungefähr einer Minute ausgelöst werden.
Angesichts der Tatsache, dass viele Wecker-Apps nicht mehr wie früher funktionieren, fehlt meiner Meinung nach etwas in den Dokumenten. Ein Beispiel für solche Apps ist die beliebte Timely- App, die von Google gekauft wurde, aber nie neue Updates erhalten hat, um die neuen Einschränkungen zu erfüllen. Jetzt möchten Benutzer sie zurück. . Einige beliebte Apps funktionieren jedoch einwandfrei, wie z. B. diese .
Was ich versucht habe
Um zu testen, ob der Alarm tatsächlich funktioniert, führe ich diese Tests durch, wenn ich in einer Minute nach der ersten Installation der App versuche, den Alarm auszulösen, während das Gerät mit dem PC verbunden ist (um die Protokolle anzuzeigen):
- Testen Sie, ob sich die App im Vordergrund befindet und für den Benutzer sichtbar ist. - dauerte 1-2 Minuten.
- Der Test, wann die App in den Hintergrund gesendet wurde (z. B. über die Home-Taste), dauerte ca. 1 Minute
- Testen Sie, wann die Aufgabe der App aus den letzten Aufgaben entfernt wurde. - Ich habe mehr als 20 Minuten gewartet und nicht gesehen, dass der Alarm ausgelöst wurde, als ich in Protokolle schrieb.
- Wie # 3, aber auch den Bildschirm ausschalten. Es wäre wahrscheinlich schlimmer ...
Ich habe versucht, die nächsten Dinge zu verwenden, alle funktionieren nicht:
alarmManager.setAlarmClock(AlarmManager.AlarmClockInfo(timeToTrigger, pendingIntent), pendingIntent)
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
Kombination einer der oben genannten, mit:
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) alarmManager.setWindow(AlarmManager.RTC_WAKEUP, 0, 60 * 1000L, pendingIntent)
Es wurde versucht, einen Dienst anstelle von BroadcastReceiver zu verwenden. Auch einen anderen Prozess ausprobiert.
Ich habe versucht, die App aus der Batterieoptimierung zu ignorieren (hat nicht geholfen), aber da andere Apps sie nicht benötigen, sollte ich sie auch nicht verwenden.
Versucht damit:
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP)
alarmManager.setAlarmClock(AlarmManager.AlarmClockInfo(timeToTrigger, pendingIntent), pendingIntent)
AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
- Es wurde versucht, einen Dienst mit dem Auslöser onTaskRemoved zu haben , um den Alarm dort neu zu planen, aber dies hat auch nicht geholfen (der Dienst hat jedoch einwandfrei funktioniert).
In Bezug auf die Google Clock-App habe ich nichts Besonderes gesehen, außer dass eine Benachrichtigung angezeigt wird, bevor sie ausgelöst wird, und ich sehe sie auch nicht im Abschnitt "Nicht optimiert" des Bildschirms mit den Einstellungen für die Batterieoptimierung.
Sehen , dass dies wie ein Bug scheint, berichten ich dies etwa hier , darunter ein Beispielprojekt und Video , das Problem zu zeigen.
Ich habe mehrere Versionen des Emulators überprüft und es scheint, dass dieses Verhalten von API 27 (Android 8.1 - Oreo) aus gestartet wurde. Wenn ich mir die Dokumente ansehe, sehe ich nicht, dass AlarmManager erwähnt wird, sondern es wurde über verschiedene Hintergrundarbeiten geschrieben.
Die Fragen
Wie stellen wir etwas ein, das heutzutage zu einem relativ genauen Zeitpunkt ausgelöst wird?
Wie kommt es, dass die oben genannten Lösungen nicht mehr funktionieren? Vermisse ich etwas Genehmigung? Vielleicht soll ich stattdessen einen Arbeiter benutzen? Aber würde es dann nicht bedeuten, dass es möglicherweise nicht rechtzeitig ausgelöst wird?
Wie überwindet die Google "Clock" -App all dies und wird trotzdem immer genau zur richtigen Zeit ausgelöst, selbst wenn sie erst vor einer Minute ausgelöst wurde? Ist es nur, weil es eine System-App ist? Was ist, wenn es als Benutzer-App auf einem Gerät installiert wird, auf dem es nicht integriert ist?
Wenn Sie sagen , dass es ist , weil es sich um eine System - App ist, habe ich eine andere App gefunden , die einen Alarm zweimal in 2 Minuten auslösen können, hier , obwohl ich denke , es manchmal ein Vordergrund Dienst verwenden können.
EDIT: eine winzige Github - Repository , um zu versuchen Ideen auf, machte hier .
BEARBEITEN: Endlich ein Beispiel gefunden , das sowohl Open-Source ist als auch dieses Problem nicht hat. Leider ist es sehr komplex und ich versuche immer noch herauszufinden, was es so anders macht (und welchen minimalen Code ich meinem POC hinzufügen sollte), damit die Alarme nach dem Entfernen der App aus den letzten Aufgaben geplant bleiben