I am writing a little Android app that will send alarms to the user based on certain rules. For this there are certain things that I need:
- I want to have something that will run periodically and check my DB to see if there are any alarms I should send to the user.
- I want this to run even if my app is closed or the phone is asleep
- I want this to start automatically every time the phone is turned on
I did a little research and these are the pieces we need:
- Services – To have our app do something in the background
- AlarmManager – To schedule the service to be executed in the future
- ACTION_BOOT_COMPLETED – This is a broadcast intent that Android sends when it boots
Now, lets start putting things together.
Service
To create a Service we just need to create a class that extends Service. This is an abstract class so you need to implement onBind:
1
2
3
4
5
6
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
We want our service to do something as soon as it is created so we overwrite the onStartCommand method:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class MyService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Query the database and show alarm if it applies
// Here you can return one of some different constants.
// This one in particular means that if for some reason
// this service is killed, we don't want to start it
// again automatically
return START_NOT_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
Now that we have our service, we need to have it start when we want it to start:
- When the app is launched
- When the phone is turned on
- Every time we schedule it to start
For the service to launch when the app is started you can simply add this line to the onCreate method of your main activity:
1
startService(new Intent(this, MyService.class));
For starting the service when the phone is turned on you will have to register a BroadcastReceiver to listen for BOOT_COMPLETE. First lets create the BroadcastReceiver:
1
2
3
4
5
6
public class AutoStart extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context, MyService.class));
}
}
The only thing this BroadcastReceiver does is start the service when it receives an Intent. Now we need to tell our manifest that we want this class to listen to boot complete:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="some.app"
android:versionCode="1"
android:versionName="1.0" >
<!-- Some more stuff in here -->
<!-- We need permission to listen to boot_completed -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application>
<!-- Some more stuff in here -->
<!-- Here we specify that we want to send BOOT_COMPLETED to our
AutoStart class -->
<receiver android:name=".AutoStart">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
</manifest>
Now, for starting our service based on a schedule requires us to use AlarmManager, so lets take a look at it.
AlarmManager
AlarmManager allows you to schedule an Intent to be triggered in the future. Most specifically we will use the AlamManager.set(int type, long triggerAtMillis, PendingIntent operation) method to have am Intent be fired in the future:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
AlarmManager alarm = (AlarmManager)getSystemService(ALARM_SERVICE);
alarm.set(
// This alarm will wake up the device when System.currentTimeMillis()
// equals the second argument value
alarm.RTC_WAKEUP,
System.currentTimeMillis() + (1000 * 60 * 60), // One hour from now
// PendingIntent.getService creates an Intent that will start a service
// when it is called. The first argument is the Context that will be used
// when delivering this intent. Using this has worked for me. The second
// argument is a request code. You can use this code to cancel the
// pending intent if you need to. Third is the intent you want to
// trigger. In this case I want to create an intent that will start my
// service. Lastly you can optionally pass flags.
PendingIntent.getService(this, 0, new Intent(this, MyService.class), 0)
);
Now, almost everything is in place, we just need to put it together:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class MyService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Query the database and show alarm if it applies
// I don't want this service to stay in memory, so I stop it
// immediately after doing what I wanted it to do.
stopSelf();
return START_NOT_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
// I want to restart this service again in one hour
AlarmManager alarm = (AlarmManager)getSystemService(ALARM_SERVICE);
alarm.set(
alarm.RTC_WAKEUP,
System.currentTimeMillis() + (1000 * 60 * 60),
PendingIntent.getService(this, 0, new Intent(this, MyService.class), 0)
);
}
}
android
java
mobile
programming
]