Managing Background Tasks on Android using the Alarm Manager
November 27th, 2011 by Micha KopsIn today’s tutorial we’re going to take a look on how to handle periodically scheduled tasks on our Android device by using BroadcastReceivers, Services and the AlarmManager.
Contents
Prerequisites
The following environment is needed to follow this tutorial …
- Java Development Kit 6
- Android SDK
- An AVM with at least Android 2.2 / API Version 8
- I recommend using Eclipse with the ADT Plugin installed
The Concept
We’re going to create a first broadcast receiver that gets initiated at boot time. This component then should make use of Android’s AlarmManager API and schedule a cyclic task using an explicit intent.
A second broadcast receiver handles this intent and starts the final service.
The first Receiver
The following receiver instanciates the AlarmManager and instructs him to send off an intent every 20 seconds.
package com.hascode.android; import java.util.Calendar; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; public class SchedulerSetupReceiver extends BroadcastReceiver { private static final String APP_TAG = "com.hascode.android"; private static final int EXEC_INTERVAL = 20 * 1000; @Override public void onReceive(final Context ctx, final Intent intent) { Log.d(APP_TAG, "SchedulerSetupReceiver.onReceive() called"); AlarmManager alarmManager = (AlarmManager) ctx .getSystemService(Context.ALARM_SERVICE); Intent i = new Intent(ctx, SchedulerEventReceiver.class); // explicit // intent PendingIntent intentExecuted = PendingIntent.getBroadcast(ctx, 0, i, PendingIntent.FLAG_CANCEL_CURRENT); Calendar now = Calendar.getInstance(); now.add(Calendar.SECOND, 20); alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, now.getTimeInMillis(), EXEC_INTERVAL, intentExecuted); } }
This is the receiver’s declaration in our AndroidManifest.xml. Please note that we’re filtering for two intents: action.BOOT_COMPLETED and action.USER_PRESET and we’re forcing the receiver to run in a specific process: “:hascode_process“. The following receiver and services are also running in this process.
<receiver android:name="SchedulerSetupReceiver" android:process=":hascode_process"> <intent-filter > <action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.USER_PRESENT" /> </intent-filter> </receiver>
Catching the Intent
Now we’re creating a second broadcast receiver to catch our explicit intent fired from the AlarmManager.
This class does not do much here – it’s just starting the final class – our service
package com.hascode.android; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; public class SchedulerEventReceiver extends BroadcastReceiver { private static final String APP_TAG = "com.hascode.android"; @Override public void onReceive(final Context ctx, final Intent intent) { Log.d(APP_TAG, "SchedulerEventReceiver.onReceive() called"); Intent eventService = new Intent(ctx, SchedulerEventService.class); ctx.startService(eventService); } }
That’s how the receiver is declared in our AndroidManifest.xml
<receiver android:name="SchedulerEventReceiver" android:process=":hascode_process"/>
Creating the Service
And last but not least the service is executed. There is only one specialty here .. we’re using onStartCommand instead of onStart and we’re returning Service.START_NOT_STICKY. First of all – onStart is deprecated in Android 2.0 and has no return value.
The return value of onStartCommand allows us to specify what to do when our Service is killed. In our case, START_NOT_STICKY tells the operating system that it may forget about the service if it has to kill it .. in our scenario this is not really a problem because the next tick from the AlarmManager will be creating a new instance (indirectly) anyway …
package com.hascode.android; import java.util.Date; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.util.Log; public class SchedulerEventService extends Service { private static final String APP_TAG = "com.hascode.android.scheduler"; @Override public IBinder onBind(final Intent intent) { return null; } @Override public int onStartCommand(final Intent intent, final int flags, final int startId) { Log.d(APP_TAG, "event received in service: " + new Date().toString()); return Service.START_NOT_STICKY; } }
And the service’s declaration in the manifest
<service android:name="SchedulerEventService" android:process=":hascode_process"/>
Just to be sure – here is my complete AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest package="com.hascode.android" android:versionCode="1" android:versionName="1.0" xmlns:android="http://schemas.android.com/apk/res/android"> <uses-sdk android:minSdkVersion="8" /> <application android:debuggable="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name"> <service android:name="SchedulerEventService" android:process=":hascode_process"> </service> <receiver android:name="SchedulerEventReceiver" android:process=":hascode_process"> </receiver> <receiver android:name="SchedulerSetupReceiver" android:process=":hascode_process"> <intent-filter > <action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.USER_PRESENT" /> </intent-filter> </receiver> </application> </manifest>
Running the Service
If you’re running the project on your device or using the emulator you should be able to see an output similar to this using logcat or DDMS
Tutorial Sources
I have put the source from this tutorial on my Bitbucket repository – download it there or check it out using Mercurial:
hg clone https://bitbucket.org/hascode/android-scheduling-tutorial
Resources
- Android Developers: Services
- Android Developers: Processes and Threads
- Android API: BroadcastReceiver
import java.util.Calendar;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class SchedulerSetupReceiver extends BroadcastReceiver {
private static final String APP_TAG = “com.hascode.android”;
private static final int EXEC_INTERVAL = 20 * 1000;
@Override
public void onReceive(final Context ctx, final Intent intent) {
Log.d(APP_TAG, “SchedulerSetupReceiver.onReceive() called”);
AlarmManager alarmManager = (AlarmManager) ctx
.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(ctx, SchedulerEventReceiver.class); // explicit
// intent
PendingIntent intentExecuted = PendingIntent.getBroadcast(ctx, 0, i,
PendingIntent.FLAG_CANCEL_CURRENT);
Calendar now = Calendar.getInstance();
now.add(Calendar.SECOND, 20);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
now.getTimeInMillis(), EXEC_INTERVAL, intentExecuted);
}
}
Tags: alarm, Android, background-task, broadcast, service
January 22nd, 2012 at 2:09 pm
Thank you!
By far the best tutorial on Android services!
March 6th, 2012 at 10:21 pm
Please change these colours, black/white its killing my eyes, good tut tho.
March 7th, 2012 at 12:37 pm
thanks – I could have used white on yellow or purple on red ! ;)
March 15th, 2012 at 5:50 pm
Great tutorial, thank you very much!
March 30th, 2012 at 10:13 am
A big thanks for the codes. Working fine.
I just want to ask why does the Alarm Manager time, (Exec Interval) doesn’t run properly.
It calls EventReceiver every 10 seconds. And I can’t change it.
Any help there would be a very big help.. Thanks in advance. :D
March 30th, 2012 at 6:48 pm
that’s strange .. did you set EXEC_INTERVAL correctly? on what target platform are you running the application?
June 9th, 2012 at 4:46 pm
I try to run this project, but nothing happens. Which is the condition to run?
Thanks a lot.
June 9th, 2012 at 6:48 pm
you should be able to see some log output using logcat or in your DDMS perspective – this does not work in your environment?
September 20th, 2012 at 11:03 am
How do i start it from my main thread? is it only necessary to start the first receiver from my main activity?
December 18th, 2012 at 5:10 pm
I tried the tutorial above but not working. I don’t see any logs on my log cat. Do i need a set permissions to allow it receive boot complete or what other permissions do i need to set?
August 20th, 2014 at 5:14 am
Thanks for the tutorial. I downloaded and ran the code. But do not see any log messages in the logcat. I changed the android target version to 19. Can you please help?
November 11th, 2014 at 9:53 am
best guide ever!! thanks bro..
November 19th, 2014 at 9:01 am
Not Working. Alarm Manager seems not working/executing. Any Clue!
February 14th, 2015 at 12:39 pm
I have try this code but not displaying anything in logcat.
October 16th, 2015 at 1:08 pm
Excellent tutorial. But how can you stop the service apart from uninstalling the application again?
October 18th, 2015 at 7:02 pm
Hi,
something like this should work:
Intent stopIntent = new Intent(this, SchedulerEventReceiver.class);
PendingIntent stopSender = PendingIntent.getBroadcast(this,
0, stopIntent, 0);
AlarmManager alarmManager = ...
alarmManager.cancel(stopSender);
September 15th, 2020 at 11:06 am
Not working in android 10