文章转载只能用于非商业性质,且不能带有虚拟货币、积分、注册等附加条件。转载须注明出处http://blog.csdn.net/flowingflying以及作者@恺风Wei。
我们在接收器中弹出Toast增加了时间标签,更好地跟踪执行时间。我们将进一步了解request code的作用。
提供一个实验例子,在此基础上调整执行的语句,看看执行的情况。
public void scheduleSameIntentMultiTimes(){
Calendar cal1 = Utils.getTimeAfterInSecs(5);
Calendar cal2 = Utils.getTimeAfterInSecs(10);
Calendar cal3 = Utils.getTimeAfterInSecs(15);
Calendar cal4 = Utils.getTimeAfterInSecs(20);
Calendar cal5 = Utils.getTimeAfterInSecs(8);
mReport.reportBack(tag, "1:schedule at " + Utils.getDateTimeString(cal1));
mReport.reportBack(tag, "2:schedule at " + Utils.getDateTimeString(cal2));
mReport.reportBack(tag, "3:schedule at " + Utils.getDateTimeString(cal3));
mReport.reportBack(tag, "4:schedule at " + Utils.getDateTimeString(cal4));
//mReport.reportBack(tag, "5:schedule repeated at " + Utils.getDateTimeString(cal5)+",间隔5秒");
Intent intent1 = new Intent(mContext,TestReceiver.class);
intent1.putExtra("message", "1:Same intent multi times");
Intent intent2 = new Intent(mContext,TestReceiver.class);
intent2.putExtra("message", "2:Same intent multi times");
Intent intent3 = new Intent(mContext,TestReceiver.class);
intent3.putExtra("message", "3:Same intent multi times");
Intent intent4 = new Intent(mContext,TestReceiver.class);
intent4.putExtra("message", "4:Same intent multi times");
Intent intent5 = new Intent(mContext,TestReceiver.class);
intent5.putExtra("message", "5:repeated");
PendingIntent pi1 = PendingIntent.getBroadcast(mContext, REQUEST_MULTI_CODE, intent1, 0);
PendingIntent pi2 = PendingIntent.getBroadcast(mContext, REQUEST_MULTI_CODE+1, intent2, 0);
PendingIntent pi3 = PendingIntent.getBroadcast(mContext, REQUEST_MULTI_CODE+2, intent3, 0);
PendingIntent pi4 = PendingIntent.getBroadcast(mContext, REQUEST_MULTI_CODE+3, intent4, 0);
//PendingIntent pi5 = PendingIntent.getBroadcast(mContext, REQUEST_MULTI_CODE+4, intent5, 0);
AlarmManager am = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP,cal1.getTimeInMillis(),pi1);
am.set(AlarmManager.RTC_WAKEUP,cal2.getTimeInMillis(),pi2);
am.set(AlarmManager.RTC_WAKEUP,cal3.getTimeInMillis(),pi3);
am.set(AlarmManager.RTC_WAKEUP,cal4.getTimeInMillis(),pi4);
//am.setRepeating(AlarmManager.RTC_WAKEUP, cal5.getTimeInMillis(), 5000, pi5);
}
我们设置了5个告警(其中1个在代码中注销,将在后面的测试中使用),对应5个不同的PendingIntent。为了区分所携带的intent,分别设置了不同的extras。
不同的request code可以用于区分不同的alarm,在上面的例子中,我们可以预测四个alarm将依次触发接收器。执行结果如下图:
我们发现,根据我们的设置的告警时间,依次顺序发出告警1,告警2,告警3,告警4,但是仔细查看告警发生的时间,确并不准确,和我们设定的时间不同。我们通过减少alarm的设定,发现设定1个告警、2个告警和3个告警的情况下,发送告警的时间和设定基本符合,由此怀疑这只是模拟器性能不足的缘故。因此,我们接了该真实设备进行调测,发现4个告警的发生时间是准确的。
在request code不同时,alarm管理器能够按我们设置的情况进行告警发送。
我们将看看request code一样,会发生什么。首先设置request code相同:
PendingIntent pi1 = PendingIntent.getBroadcast(mContext, REQUEST_MULTI_CODE, intent1, 0);
PendingIntent pi2 = PendingIntent.getBroadcast(mContext, REQUEST_MULTI_CODE, intent2, 0);
PendingIntent pi3 = PendingIntent.getBroadcast(mContext, REQUEST_MULTI_CODE, intent3, 0);
PendingIntent pi4 = PendingIntent.getBroadcast(mContext, REQUEST_MULTI_CODE, intent4, 0);
PendingIntent pi5 = PendingIntent.getBroadcast(mContext, REQUEST_MULTI_CODE, intent5, 0);
为了避免过多alarm进行干扰,我们注销了代码,只留下需要观察的对象。
代码片段:实验一
PendingIntent pi1 = PendingIntent.getBroadcast(mContext, REQUEST_MULTI_CODE, intent1, 0);
PendingIntent pi2 = PendingIntent.getBroadcast(mContext, REQUEST_MULTI_CODE, intent2, 0);
... ...
am.set(AlarmManager.RTC_WAKEUP,cal1.getTimeInMillis(),pi1);
am.set(AlarmManager.RTC_WAKEUP,cal2.getTimeInMillis(),pi2);
代码片段:实验二
PendingIntent pi1 = PendingIntent.getBroadcast(mContext, REQUEST_MULTI_CODE, intent1, 0);
PendingIntent pi5 = PendingIntent.getBroadcast(mContext, REQUEST_MULTI_CODE, intent5, 0);
... ...
am.set(AlarmManager.RTC_WAKEUP,cal1.getTimeInMillis(),pi1);
am.setRepeating(AlarmManager.RTC_WAKEUP, cal5.getTimeInMillis(), 5000, pi5);
代码片段:实验三
PendingIntent pi1 = PendingIntent.getBroadcast(mContext, REQUEST_MULTI_CODE, intent1, 0);
PendingIntent pi5 = PendingIntent.getBroadcast(mContext, REQUEST_MULTI_CODE, intent5, 0);
... ...
am.setRepeating(AlarmManager.RTC_WAKEUP, cal5.getTimeInMillis(), 5000, pi5);
am.set(AlarmManager.RTC_WAKEUP,cal1.getTimeInMillis(),pi1);
代码片段:实验四
PendingIntent pi2 = PendingIntent.getBroadcast(mContext, REQUEST_MULTI_CODE, intent2, 0);
PendingIntent pi1 = PendingIntent.getBroadcast(mContext, REQUEST_MULTI_CODE, intent1, 0);
... ...
am.set(AlarmManager.RTC_WAKEUP,cal1.getTimeInMillis(),pi1);
am.set(AlarmManager.RTC_WAKEUP,cal2.getTimeInMillis(),pi2);
测试结果如下:
在request code相同的情况下,告警的执行时间,和执行模式(单次还是重复)按后设置的告警,告警内容(intent)则按代码中第一次加入该request code的pendingIntent的intent。
关于intent的问题,在之前取消告警中提过:extras不用于判断intent的唯一性。在小例子中,实际上系统会认为intent都是相同的,因此没有进行intent的更新。我们增加一个接收器TestReceiver2,用于确保系统能区分intent,实验五的相关代码如下:
Calendar cal1 = Utils.getTimeAfterInSecs(5);
Calendar cal2 = Utils.getTimeAfterInSecs(10);
Intent intent1 = new Intent(mContext,TestReceiver.class);
intent1.putExtra("message", "1:Same intent multi times");
Intent intent2 = new Intent(mContext,TestReceiver2.class);
intent2.putExtra("message", "2:Same intent multi times");
PendingIntent pi1 = PendingIntent.getBroadcast(mContext, REQUEST_MULTI_CODE, intent1, 0);
PendingIntent pi2 = PendingIntent.getBroadcast(mContext, REQUEST_MULTI_CODE, intent2, 0);
AlarmManager am = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP,cal1.getTimeInMillis(),pi1);
am.set(AlarmManager.RTC_WAKEUP,cal2.getTimeInMillis(),pi2);
试验的结果是:系统能正确执行两次告警触发,如同request code不一样的情况。
根据上面的多个测试,我们的结论是:告警可以通过pendingIntent携带的不同的intent或者request code来进行区分。注意extras不用于区分intent,而是在创建intent对象所携带的参数。如果系统无法区pendingIntent,则按后面设置的告警来执行,但在这过程中并不更新所携带的intent信息。
从源码看,对并不更新所携带intent信息有些奇怪,因为在AlarmManagerService.java的L578(API 19)执行了removeLocked(operation),其中opteration就是PendingIntent对象。但是不清楚服务中这个PendingIntent是如何生产的,也不确定未来的版本会不会进行修订。因此,除非有特别的需求,一般不要使用相同的request code和相同的intent。
需要注意,设备重启后,alarm管理器中所设置的都会变成无效。如果我们需要alarm能够在开机后依然有效,就不能光依赖于alarm manager。我们需要对此进行相关的保存,并在重启的时候重新向alarm管理器进行注册。或者设备重启,可以通过监听android.intent.action.BOOT_COMPLETED广播消息。
小例子代码在:Pro Android学习:Alarm Manager小例子
相关链接:我的Android开发相关文章