关闭

android 之 AlarmManager 系统闹钟(3)

166人阅读 评论(0) 收藏 举报
分类:

文章转载只能用于非商业性质,且不能带有虚拟货币、积分、注册等附加条件。转载须注明出处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

不同的request code可以用于区分不同的alarm,在上面的例子中,我们可以预测四个alarm将依次触发接收器。执行结果如下图:

我们发现,根据我们的设置的告警时间,依次顺序发出告警1,告警2,告警3,告警4,但是仔细查看告警发生的时间,确并不准确,和我们设定的时间不同。我们通过减少alarm的设定,发现设定1个告警、2个告警和3个告警的情况下,发送告警的时间和设定基本符合,由此怀疑这只是模拟器性能不足的缘故。因此,我们接了该真实设备进行调测,发现4个告警的发生时间是准确的。

在request code不同时,alarm管理器能够按我们设置的情况进行告警发送。

request code相同的情况

我们将看看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小例子

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:12515次
    • 积分:241
    • 等级:
    • 排名:千里之外
    • 原创:6篇
    • 转载:40篇
    • 译文:0篇
    • 评论:0条