在Android中,可以使用闹钟管理器来触发事件,包括广播BroadcastReceiver,服务Service和活动Activity。这些事件可以在特定的时刻或者以固定的时间间隔来触发。
使用闹钟管理器一般有以下几个步骤:
1、获取到闹钟管理器的服务,即AlarmManager;
2、确定设置闹钟的时刻;
3、创建要调用的接收程序,可以是广播BroadcastReceiver,服务Service和活动Activity;
4、创建一个挂起的Intent(即PendingIntent),它可传递给闹钟管理器来调用设置的该接收程序;
5、使用第2步中的时间和第4步中的Intent来设置闹钟;
6、在第3步中的接收闹钟管理器的调用。
接下来是对每个步骤进行说明:
1、获取闹钟管理器,AlarmManager
这是比较简单的,调用系统服务就可以得到AlarmManager。
1. AlarmManager am = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
2、创建闹钟的时刻
为了快捷方便,特别创建了一个Utils类,在里面提供创建各种类型的时刻。
1. public class Utils
2. {
3. /**
4. * 创建secs秒后闹钟时间
5. * @param secs
6. * @return
7. */
8. public static Calendar getTimeAfterInSecs(int secs)
9. {
10. Calendar cal = Calendar.getInstance();
11. cal.add(Calendar.SECOND,secs);
12. return cal;
13. }
14. public static Calendar getCurrentTime()
15. {
16. Calendar cal = Calendar.getInstance();
17. return cal;
18. }
19. /**
20. * 创建在某个固定小时时刻的闹钟
21. * @param hours
22. * @return
23. */
24. public static Calendar getTodayAt(int hours)
25. {
26. Calendar today = Calendar.getInstance();
27. Calendar cal = Calendar.getInstance();
28. cal.clear();
29.
30. int year = today.get(Calendar.YEAR);
31. int month = today.get(Calendar.MONTH);
32. //represents the day of the month
33. int day = today.get(Calendar.DATE);
34. 0,0);
35. return cal;
36. }
37. public static String getDateTimeString(Calendar cal)
38. {
39. new SimpleDateFormat("MM/dd/yyyy hh:mm:ss");
40. false);
41. String s = df.format(cal.getTime());
42. return s;
43. }
44. }
3、创建接受闹钟的接收程序,这里暂时使用一种类型BroadCastReceiver
1. public class TestReceiver extends BroadcastReceiver
2. {
3. private static final String tag = "TestReceiver";
4. @Override
5. public void onReceive(Context context, Intent intent)
6. {
7. "TestReceiver", "intent=" + intent);
8. "message");
9. Log.d(tag, message);
10. }
11. }
4、创建闹钟的PendingIntent
首先需要创建只想TestReceiver的Intent
1. Intent intent = new Intent(mContext, TestReceiver.class);
2. ent.putExtra("message", "Single Shot Alarm");
接下来创建挂起的PendingIntent:
1. PendingIntent pi =
2. ndingIntent.getBroadcast(
3. mContext, //context
4. 1, //request id, used for disambiguating this intent
5. //intent to be delivered
6. //pending intent flags
5、设置闹钟
1. Calendar cal = Utils.getTimeAfterInSecs(30);
2. AlarmManager am = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
3. am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pi);
这样就可以在TestReiver中接收到闹钟消息了。
以上是关于闹钟管理器的简单使用,接下来将增加关于设置重复闹钟和取消闹钟的使用。
一、设置重复闹钟
设置重复闹钟的前面几个步骤都是一样的,只是在最后设置闹钟的时候有所变化
1. am.setRepeating(AlarmManager.RTC_WAKEUP,
2. cal.getTimeInMillis(),
3. 5*1000, //5 secs
4. pi);
关于这个方法的参数说明:第一个:警报的类型,这里采用闹钟来唤醒设备;第二个:第一次闹钟执行的时刻;第三个:在闹钟第一次执行后,每隔多久开始重复执行;第四个:挂起的PendingIntent。
二、取消闹钟
要取消闹钟,必须首先挂起一个Intent,然后调用cancel()方法,将参数传递给闹钟管理器。
1. Intent intent =
2. new Intent(this.mContext, TestReceiver.class);
3.
4. //To cancel, extra is not necessary to be filled in
5. //intent.putExtra("message", "Repeating Alarm");
6.
7. this.getDistinctPendingIntent(intent, 2);
8.
9. // Schedule the alarm!
10. AlarmManager am =
11. (AlarmManager)
12. this.mContext.getSystemService(Context.ALARM_SERVICE);
13. am.cancel(pi);
1. protected PendingIntent getDistinctPendingIntent(Intent intent, int requestId)
2. {
3. PendingIntent pi =
4. PendingIntent.getBroadcast(
5. //context
6. //request id
7. //intent to be delivered
8. 0);
9.
10. //pending intent flags
11. //PendingIntent.FLAG_ONE_SHOT);
12. return pi;
13. }
在创建Intent的时候,如果是为了取消闹钟,可以不用再Intent中设置任何消息参数和数据,只需要保证最后的指向接收程序一致。然后创建的PendingIntent也必须和原来一致,必须确保采用设置闹钟时相同的方式来构造它,包括请求代码,即上面的requestId和接收程序。
三、设置多个闹钟
如果了解了上面关于设置单个闹钟和重复闹钟的设置过程,可能会认为只需要创建多个不同的cal时刻,然后分别设置到闹钟里面,就能实现了。其实不然,里面涉及到一些陷进。
先看下面的代码:
1. /*
2. * Same intent cannot be scheduled multiple times.
3. * If you do, only the last one will take affect.
4. *
5. * Notice you are using the same request id.
6. */
7. public void scheduleSameIntentMultipleTimes()
8. {
9. //Get the instance in time that is
10. //30 secs from now.
11. 30);
12. 35);
13. 40);
14. 45);
15.
16. //If you want to point to 11:00 hours today.
17. //Calendar cal = Utils.getTodayAt(11);
18.
19. //Get an intent to invoke
20. //TestReceiver class
21. "color:#FF0000;">Intent intent = new Intent(mContext, TestReceiver.class);
22. "message", "Single Shot Alarm");</span>
23. "color:#FF0000;">PendingIntent pi = this.getDistinctPendingIntent(intent, 1);</span>
24.
25. // Schedule the alarm!
26. AlarmManager am = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
27.
28. am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pi);
29. am.set(AlarmManager.RTC_WAKEUP, cal2.getTimeInMillis(), pi);
30. am.set(AlarmManager.RTC_WAKEUP, cal3.getTimeInMillis(), pi);
31. am.set(AlarmManager.RTC_WAKEUP, cal4.getTimeInMillis(), pi);
32. }
上面这部分代码,使用了同一个PendingIntent,设置了4个不同的闹钟时间,这样的效果就是:
只有最后一个闹钟会被触发,前面的所有闹钟都会被忽略掉。
而要实现多个闹钟的实现是如下:
1. /*
2. * Same intent can be scheduled multiple times
3. * if you change the request id on the pending intent.
4. * Request id identifies an intent as a unique intent.
5. */
6. public void scheduleDistinctIntents()
7. {
8. //Get the instance in time that is
9. //30 secs from now.
10. 30);
11. 35);
12. 40);
13. 45);
14.
15. //If you want to point to 11:00 hours today.
16. //Calendar cal = Utils.getTodayAt(11);
17.
18. //Get an intent to invoke
19. //TestReceiver class
20. new Intent(mContext, TestReceiver.class);
21. "message", "Single Shot Alarm");
22.
23. // Schedule the alarms!
24. AlarmManager am = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
25.
26. 1));
27. 2));
28. 3));
29. 4));
每个挂起的Intent,也就是PendingIntent不同,也就是让每个PendingIntent的RequestId不同。产生这种原因是因为在AlarmManager中设置闹钟时,对于相同的Intent,是通过不同的请求Id来创建的。
在相同类型的Intent上设置闹钟时,只有最后一个闹钟时生效的。
以下是AlarmMangerService的部分源码,可以看到为什么不能使用相同的PendingIntent了。
1. public void setRepeating(int type, long triggerAtTime, long interval,
2. PendingIntent operation) {
3. .....
4. synchronized (mLock) {
5. "color:#FF0000;"> Alarm alarm = new Alarm();
6. alarm.type = type;
7. alarm.when = triggerAtTime;
8. alarm.repeatInterval = interval;
9. alarm.operation = operation;</span>
10.
11. // Remove this alarm if already scheduled.
12. "color:#FF0000;">removeLocked(operation);</span> //当使用相同的operation的时候u,就会先把已有的删除,这样的话,直到最后一个才会生效。
13.
14. if (localLOGV) Slog.v(TAG, "set: " + alarm);
15.
16. int index = addAlarmLocked(alarm);
17. if (index == 0) {
18. setLocked(alarm);
19. }
20. }
21. }
最后一点是关于闹钟的持久化问题,它们是不能保存到设备重新启动之后,也就是说当设备重新启动后,之前设置的闹钟将全部失效。