android 之 AlarmManager 系统闹钟(3)

转载 2016年08月31日 16:16:56

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

相关文章推荐

Android提供的系统服务之--AlarmManager(闹钟服务)

本节引言: 本节主要介绍的是Android系统服务中的---AlarmManager(闹钟服务), 除了开发手机闹钟外,更多的时候是作为一个全局的定时器,通常与Service 结合,在特定时间启...

AlarmManager系统闹钟

AlarmManager介绍 AlarmManager这个类提供对系统闹钟服务的访问接口。你可以为你的应用设定一个在未来某个时间唤醒的功能。当闹钟响起,实际上是系统发出了为这个闹钟注册的广播,会自动开...
  • l_user
  • l_user
  • 2016年03月18日 23:11
  • 281

Android基础入门教程——10.5 AlarmManager(闹钟服务)

本节带来的Android中的AlarmManager(闹钟服务),听名字我们知道可以通过它开发手机闹钟类的APP, 而在文档中的解释是:在特定的时刻为我们广播一个指定的Intent,简单说就是我们自...

Android中AlarmManager详解以及利用PendingIntent设置闹钟

AlarmManager是提供一种访问系统闹钟服务的方式,允许你去设置在将来的某个时间点去执行你的应用程序。当你的闹钟响起(时间到)时,在它上面注册的一个意图(Intent)将会被系统以广播发出,然后...

Android---AlarmManager(全局定时器/闹钟)指定时长或以周期形式执行某项操作

http://www.cnblogs.com/jico/archive/2010/11/03/1868361.html AlarmManager的使用机制有的称呼为全局定时器,有的称呼为闹钟。通过对...

android闹钟AlarmManager的使用

AlarmManager的作用文档中的解释是:在特定的时刻为我们广播一个指定的Intent。简单的说就是我们设定一个时间,然后在该时间到来时,AlarmManager为我们广播一个我们设定的Inten...
  • icewst
  • icewst
  • 2012年09月10日 10:14
  • 441

Android闹钟 AlarmManager基础

本次主要讲述一下android 闹钟。 AlarmManager对系统提供闹钟服务,能在设定时间唤醒应用。 先看设置只响应一次的代码: Intent intent = new Intent(...

Android---AlarmManager闹钟设置

本片文章主要介绍闹钟的管理,使用到了BroadcastReceiver。 1.在主界面上放置两个按钮,一个用于设置闹钟,一个用于取消闹钟。2.自定义BroadcastReceiver用于响应闹钟时间到...

Android闹钟 AlarmManager的使用和通知的使用

package com.zking.myalarm; import java.util.Calendar; import java.util.Date; import java.util.Loc...

Android之AlarmManager(全局定时器/闹钟)指定时长或以周期形式执行某项操作

1、AlarmManager,顾名思义,就是“提醒”,是Android中常用的一种系统级别的提示服务,可以实现从指定时间开始,以一个固定的间隔时间执行某项操作,所以常常与广播(Broadcast)连用...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:android 之 AlarmManager 系统闹钟(3)
举报原因:
原因补充:

(最多只允许输入30个字)