Services with Alarms
Overview
·
A service is required for an alarm to be processed
when the system is sleeping.
·
The idea is as follows
o The
activity starts the service. A button triggers the service to set the alarm
o The alarm
calls the OneShotAlarmReceiver,
o which calls
a BroadcastReceiver that is part of the service
o Since the
service is always able to receive broadcasts, it will be triggered even if the
system is sleeping
·
One complication is that we need to make sure that the
system stays awake long enough to call the service.
Merge FunWithLocalServices and FunWithAlarms1
·
Start with a service developed in the FunWithLocalServices tutorial
·
Open the FunWithAlarms1 files for reference
·
Merge FunWithLocalServices
and FunWithAlarms1
o Make new
class OneShotAlarmReceiver
§ Same as in
FunWithAlarms1
§ onReceive
with (note new name of action is changed to com.FunWithServices.MyService.TIMESUP
·
Log.d("OneShotAlarmReceiver","Alarm
Expired");
·
Intent broadcast=new Intent("com.FunWithServices.MyService.TIMESUP");
·
context.sendBroadcast(broadcast);
·
o In
manifest,
§ add entry
for receiver OneShotAlarmReceiver
o In MyService, add broadcast receiver
§ From FunWithAlarms1,
copy public BroadcastReceiver receiver=new BroadcastReceiver()
{…
o In MyService, add function to set the alarm and register the
BroadcastReceiver
§ public void
startAlarm()
§ {
§ registerReceiver(receiver, new
IntentFilter("com.FunWithServices.MyService.TIMESUP"));
§ Intent intent
= new Intent(this, OneShotAlarmReceiver.class);
§ PendingIntent pendingIntent
= PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
§ AlarmManager alarmManager
= (AlarmManager) getSystemService(Context.ALARM_SERVICE);
§ alarmManager.set(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + (5 * 1000), pendingIntent);
§ Log.d("MyService","Alarm
is set");
§ }
o In MyService.onDestroy(), add
§ unregisterReceiver(receiver);
o In FunWithLocalServices, call startAlarm
from button onClickListener
§ Add myService.startAlarm();
·
Run
Problem with
sleeping
·
When an activity or service is running, the system
might sleep at any time
·
In order to keep the system awake, WakeLocks
are used
·
So, when the alarm goes off and the service’s
broadcast receiver is triggered, it should set a WakeLock.
·
The alarm’s BroadcastReceiver does not need a WakeLock, the AlarmManager keeps a WakeLock
so the system does not sleep before the BroadcastReceiver.onReceive
is complete
·
However, the
system is allowed to sleep as soon as the alarms BroadcastReceiver
is finished.
·
It might go to sleep before the service is able set
its WakeLock
·
We need to call a WakeLock
from the alarm’s BroadcastReceiver.onReceive, but
then release it from the services BroadcastReceiver.
·
One way to solve this is to make a class with static
member variables and functions.
MyStaticWakeLock class
·
Make new class call MyStaticWakeLock
o public
class MyStaticWakeLock {
o private static PowerManager.WakeLock
wl = null;
o public static void lockOn(Context context) {
o PowerManager
pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
o if (wl==
null)
o wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "MyStaticWakeLock");
o wl.acquire();
o }
o public static void lockOff(Context context) {
o PowerManager
pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
o if (wl
!= null)
o wl.release();
o }
o }
·
Note, this class has two functions, one for setting the
WakeLock and one for releasing
·
In OneShotAlarmReceiver.onReceive, add
o MyStaticWakeLock.lockOn();
·
At the end of MyService.receiver.onReceive(),
add
o MyStaticWakeLock.lockOff();
·
Run