Manche Applikationen erfordern, dass periodisch Tasks ausgeführt werden – auch wenn die Applikation selber gar nicht (mehr) ausgeführt wird. Der wahrscheinlichste praktische Anwendungsfall dürfte ein automatisiertes Update sein, das im Hintergrund Daten von einem Server nachläd und den User ggf. über neue Daten (wie z.B. eine neue Email) informiert.
Speziell auf Smartphones, die bekanntlicherweise nicht die allergrösste Ausdauer in Sachen Laufzeit besitzen ist man hier gut beraten, keinen seraraten Remote Service zu nutzen. Ein solcher würde auch nach dem Beenden der App weiter im Hintergrund arbeiten und darauf "warten", dass der Zeitpunkt für die nächste Aktion gekommen ist. Eine gute Lösung sieht anders aus – insbesondere wenn man Akku, CPU und RAM schonen will...
Android bietet für solche Zwecke einen AlarmManager an, der sich wunderbar als Cronjob-Manager missbrauchen lässt. Diesem teilt man einfach mit, wann die gewünschte Aktion ausgeführt werden soll:
public class JobScheduler extends BroadcastReceiver { /** * sets the timer for the next update interval */ @Override public void onReceive(Context context, Intent intent) { // trigger update functionality in Job using an Intent Intent i = new Intent(context, Job.class); PendingIntent sender = PendingIntent.getBroadcast(context, 0, i, 0); Date d = getNextJobScheduleDate(); AlarmManager aManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); aManager.set(AlarmManager.RTC, d.getTime(), sender); Log.d("xenonite.net", "Next Job execution scheduled: " + d.getDay() + ", " + d.getHours() + ":" + d.getMinutes()); } /** * returns a Date object determining the time * when the next update should be executed * * @return Date object */ private Date getNextJobScheduleDate() { Date d = new Date(); // :TODO: determine and set the desired date return d; } }
Das System wird nun zum festgelegten Zeitpunkt einen BroadcastIntent versenden, den man mit einem speziellen BroadcastReceiver fängt.
public class Job extends BroadcastReceiver { /* * executes the actual job */ @Override public void onReceive(Context context, Intent intent) { // :TODO: do sth } }
Das Schöne ist, dass dieser Code vollkommen unabhängig von der eigentlichen App – und somit vom UI – ausgeführt wird und dabei keinen speicherpersistenten Service benötigt.
Damit der Job auch nach einem Neustart des Smartphones korrekt geplant wird, muss ein zusätzlicher Receiver in der AndroidManifest.xml registriert werden. Dieser sorgt dafür, dass der JobScheduler gleich nach dem booten des Smartphones ausgeführt wird.
<receiver android:name="net.xenonite.demo.JobScheduler"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"></action> </intent-filter> </receiver>
