[Gelöst] AlarmManager ab API 19 wird unregelmäßig ausgeführt

  • Antworten:13
  • Bentwortet
Bernd Roth
  • Forum-Beiträge: 98

13.11.2014, 08:23:30 via Website

Hallo Forum,
ich habe wieder einmal folgendes Problem mit dem AlarmManager.

Ab der API 19 wird der AlarmManager mit der Methode setRepeating unregelmäßig ausgeführt, weil die Alarme gebatched und dann gleichzeitig ausgeführt werden!
Jedoch benötige ich weiterhin eine punktgenaue Ausführung im Intervall von 60 Minuten und habe daher die Methode setExact verwendet und so bin ich vorgegangen, um zu einem hoffentlich positiven Ergebnis zu kommen ...

Habe in einer TreeMap alle Zeiten ab jetzt bis 25:59 gespeichert.
Danach iteriere ich über die TreeMap, in der Schleife lege ich einen eindeutigen PendingIntent an und starte die Methode setExact.
Der erste Alarm geht wie immer rechtzeitig an, aber danach passiert wieder mal gar nichts.

Leider habe ich den Code gerade nicht vorliegen.

Kann es von der Beschreibung her sein, dass das trotzdem nicht funktionieren wird oder habe ich was übersehen?
bzw. gibt es eine andere Möglichkeit zu einer bestimmten Zeit einen Alarm zu starten u dann alle weiteren 60 Minuten ( das Mobiltelefon ist aber hierbei Power Off ).
Seltsamerweise funktioniert der AlarmManager ( setRepeating Methode ) in der Version 4.2.2 bei den Samsung Note 3 ohne Probleme, bei den Nexus Geräten mit der selben Versionierung aber überhaupt nicht - woran könnte das eventuell liegen ( selber Code versteht sich! ).

Danke vielmals schon für jede Hilfe!

lG

— geändert am 17.11.2014, 20:18:57

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

13.11.2014, 08:51:46 via Website

Lies mal den aktualisieren Developer Guide dazu.
Das wurde seit Kitkat tatsächlich geändert.

Repeating Alarms sind jetzt IMMER ungenau.

Wenn ich es richtig verstanden habe, sind nur noch Alarms mit einer konkreten Uhrzeit genau.
Das dürfte dann auch dein Lösungsansatz sein.
Setze den Alarm und wenn er losgeht, setze ihn neu für Jetzt+60m.

AlarmManager.html#setRepeating(int,%20long,%20long,%20android.app.PendingIntent)

— geändert am 13.11.2014, 08:54:14

Antworten
Bernd Roth
  • Forum-Beiträge: 98

13.11.2014, 09:12:56 via Website

Hallo,
genau so habe ich es an sich gemacht.
Nur geht der erste Alarm rechtzeitig los, nachfolgende nicht mehr.

So sieht mein Code aus:

Intent intent = new Intent(this, AlarmManager.class);
PendingIntent pIntent;
AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
int id= 0;

for(long value : treeMap){
   pIntent = PendingIntent.getActivity(this, id, intent, 0);
   a.setExact(AlarmManager.RTC_WAKEUP, value.currentTimeMillis(), pIntent);
   i++;
 }

Muss ich eventuell das PendingIntent - Objekt in der Schleife erzeugen?

for( ... ){
    PendingIntent pIntent = PendingIntent.getActivity(this, id, intent, 0);
}

Oder kann es daran liegen, dass ich nur den ersten Alarm genau triggern kann und alle weiteren dann im BroadcastReceiver weiterbehandeln muss ( kann ich mir beim bestern Willen nicht vorstellen, da ja das PendingIntent - Objekt eindeutig ist u damit müsste es egal sein, wo ich es erzeuge! )?

lG

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

13.11.2014, 09:24:26 via Website

Du kannst EINEN PendingIntent nur EINMAL schedulen.
Wenn du denselben (per equals) nochmal planst, überschreibt er den alten.

Ergo: Du kannst nur die jeweils nächste Ausführung schedulen, oder du musst dafür sorgen, dass die PendingIntents NICHT equal sind.

Antworten
Bernd Roth
  • Forum-Beiträge: 98

13.11.2014, 09:37:07 via Website

Anscheinend bin ich ein wenig übernächtigt, aber ich habe mir gedacht, dass ich mit der ID im PendingIntent sorge trage,
dass das PendingIntent - Objekt eindeutig ist u somit öfters getriggert werden kann?

Wenn ich das falsch verstanden habe, gibt es dann eine Möglichkeit mein Problem zu lösen?

Antworten
Bernd Roth
  • Forum-Beiträge: 98

13.11.2014, 09:57:51 via Website

Ok, dann habe ich da etwas falsch verstanden, ich dachte mir wirklich, dass ich damit dann mehrere AlarmManager anlegen kann.
Sprich, ich muss dann im BroadcastReciever, sobald ich den Alarm bekomme auf meine TreeMap zugreifen u von dort aus die nächste Ausführung planen?

Also immer Step - by - Step sozusagen.

Ok, dann werde ich es so machen, hoffe, dass es so funktioniert ( erster Alarm wird aussen vom BroadcastReceiver getriggert wie bisher! ):

Intent intent = new Intent(this, AlarmManager.class);
PendingIntent pIntent;
AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
int id= 0;

long value= treeMap.getFirstKey();
pIntent = PendingIntent.getActivity(this, 0, intent, 0);
a.setExact(AlarmManager.RTC_WAKEUP, value.currentTimeMillis(), pIntent);

Im BroadcastReceiver werden dann die restlichen Alarm step - by - step getriggert ( ein wenig Pseudocode ):

if(intervall == "30"){
   treeMap.remove(value);
   value = treeMap.getFirstKey();
   am.setExact(AlarmManager.RTC_WAKEUP, value.currentTimeMillis(), pIntent);
}

Liege ich damit richtig?

Danke Dir vielmals für Deine Hilfe bereits!

Antworten
Bernd Roth
  • Forum-Beiträge: 98

13.11.2014, 10:25:32 via Website

Ja ich habe ein paar Informationen unterschlagen, damit es nicht zu lange wird :)
Der User kann mehrere ( unendlich viele ) AlarmManager zu unterschiedlichen Zeiten starten u diese Zeiten speichere ich in der TreeMap.

So kann es sein ( passiert auch regelmäßig ), dass der User folgendes auswählt.

Um 09:02 setze Alarm, wiederhole alle 60 Minuten und sende eine SMS mit dem Inhalt 15 Minuten
Um 09:17 setze Alarm, wiederhole alle 60 Minuten und sende eine SMS mit dem Inhalt 30 Minuten
Um 10:02 setze Alarm, wiederhole alle 90 Minuten und sende eine SMS mit dem Inhalt 60 Minuten

Das Ganze kann vom Inhalt her variieren, daher die TreeMap.
Darin speichere ich mir als Key => Wiederholung alle 60 Minuten
Value => SMS Inhalt

Je nachdem was u wieviele unterschiedliche Zeiten und Werte der User auswählt baue ich mir damit die TreeMap auf.
Wenn es natürlich noch bessere Wege gibt, bin ich nicht abgeneigt mir auch diese anzusehen!

Antworten
Bernd Roth
  • Forum-Beiträge: 98

13.11.2014, 10:53:15 via Website

Ah, danke, habe das jetzt nicht bedacht, dass die TreeMap ja aus dem Speicher fliegt, wenn die App geschlossen wird.
Dann muss ich halt in einem nächsten Schritt die Daten in eine Datenbank schreiben.

Add unterschiedliche PendingIntents:
Dann passt es eh, wenn ich im BroadcastReceiver den 2ten, 3ten, .., n PendingIntent mit einer eindeutigen ID folgendermaßen anlege:

BroadcastReceiver - Class:

int value = treeMap.getFirstKey();
PendingIntent pIntent = PendingIntent.getActivity(this, value, intent, 0);
am.setExact(AlarmManager.RTC_WAKEUP, value.currentTimeMillis(), pIntent);
treeMap.remove(value);
`

Natürlich wird der PendingIntent nicht mehr in einer Schleife angelegt, wie bereits vorher besprochen, sondern immer nur dann, wenn ein Alarm getriggert wird und er ist aufgrund der ID eindeutig!

So sollte es dann ja passen!?!?

Antworten
Bernd Roth
  • Forum-Beiträge: 98

13.11.2014, 11:21:46 via Website

IDs sind wirklich eindeutig, dafür garantiere ich :) - sind nichts anderes als die Uhrzeit in Millisekunden umgerechnet und den Wert verwende ich als ID schlussendlich.

Dann danke ich Dir vielmals für Deine Hilfe!

Werde es dann Zuhause sogleich ausprobieren u melden, wie es ausgegangen ist :)

Antworten
Bernd Roth
  • Forum-Beiträge: 98

17.11.2014, 20:16:42 via Website

Hallo,
hat bestens funktioniert.

Die Zeiten vorerst in eine TreeMap aufgenommen ( Key ==> Uhrzeit in Millisek ) u dann alles ausgelesen u die Intents zugeordnet.

Danke Dir vielmals!

lG

Antworten