Hey
manchmal ist es nötig ein Widget nicht in einem Intervall auszuführen, sondern zu festgelegten oder programmatisch berechneten Zeitpunkten.
Dafür ist es nötig im AndroidManifest eine weitere Intent Action einzutragen, die abgefangen werden soll:
<receiver android:name=".widgets.Widget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
<action android:name="mypackage.widget.MY_WIDGET_UPDATE"/> // DIESE ZEILE KOMMT HINZU
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/widget_info"/>
</receiver>
Dann gibt es noch ein paar änderungen am AppWidgetProvider:
In der onUpdate(...) funktion des AppWidgetProvider müssen wir den Ausführungszeitpunkt festlegen (es sei denn es ist ein Intervall zu festgelegen Uhrzeiten, dann kann man das auch in der onEnabled(...) machen.
function onUpdate(...) {
[...]
Time nextRun = new Time();
nextRun.setToNow();
nextRun.hour += nextRun.hour; // beispiel für programmatischen ablauf.
nextRun.normalize(false); // Time Objects müssen immer mit normalize wieder richtig gestellt werden, wenn man etwas verändert. Sehr häufige fehlerquelle.
AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(UPDATE_WIDGET); // UPDATE_WIDGET ist ein final static String der die Intent action enthält ("mypackage.widget.MY_WIDGET_UPDATE")
PendingIntent pending = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_ONE_SHOT);
alarm.set(AlarmManager.RTC, nextRun.toMillis(false), pending); // im falle des einmaligen programmatischen ablauf wird set(...) statt setInterval(...) genutzt
// kleine Erläuterung RTC bedeutet zu richtiger Uhrzeit, wenn das Handy im Sleep Mode ist also im Standby, dann wird das Update erst ausgeführt, wenn es wieder aktiv ist.
// RTC_WAKEUP wiederum würde das Handy aus dem Standby Modus holen, wenn geupdatet werden soll, was nur getan werden sollte, wenn das aktualisieren eine Weile dauern
// könnte und nicht häufig ausgeführt werden muss, da das sonst beim entsperren des Handys das Handy blockieren oder verlangsamen könnte.
// RTC ist mein Favorit, da es sehr Akkuschonend ist.
}
Alles anzeigen
Da der AlarmManager nicht die onUpdate(...) aufruft sondern die onReceive(...) muss diese funktion auch noch implementiert werden:
function onReceive(...) {
super.onReceive(context, intent);
if( UPDATE_WIDGET.equals(intent.getAction()) ) {
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); // AppWidgetManager wird instanziert
int ids[] = appWidgetManager.getAppWidgetIds(new ComponentName(context.getPackageName(), getClass().getName())); // IDs werden ausgelesen
onUpdate(context, appWidgetManager, ids); // onUpdate wird explizit aufgerufen
}
}
durch den aufruf der onUpdate(...) funktion wird der timer immerwieder neu eingestellt (bzw. er gilt ja nur einmal)
Das wichtigste ist allerdings das man den AlarmManager auch wieder abbrechen muss, da er sonst trotz entfernen aller Widgets ewig weiterlaufen würde.
Das geschieht am Besten in der onDisabled(..) funktion, die nur aufgerufen wird, wenn alle Widgets entfernt wurden
public void onDisabled(Context context) {
super.onDisabled(context);
AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(UPDATE_WIDGET);
PendingIntent pending = PendingIntent.getBroadcast(context, 0, i, PendingIntent.FLAG_ONE_SHOT);
alarm.cancel(pending);
}
Damit kann man relativ einfach zu jeder beliebiegen Zeit updaten, zum Beispiel Dienstags immer um 17 Uhr und Mittwoch um 18 Uhr ( das wiederum wäre am besten mit einem Intervall in der onEnabled geregelt).
Noch ein Fehler der auftreten könnte: Wenn man den Updatezeitpunkt ausversehen immer in der Vergangenheit wählt, dann wird der "Alarm" nachgeholt und wieder ein Alarm gesetzt nachgeholt etc...
Das wird das Handy daran hindern in den Standby Mode zu wechseln und innerhalb von ein paar Stunden den gesamten Akku "fressen".