最近再做一个项目需要用到Android中的闹钟提醒,在这个过程中遇到很多问题,今天在这里总结分享给大家,希望能对读者有所帮助:

我们都知道Android总共有三种内置的闹钟类型,如下:

(1)set(int type,long startTime,PendingIntent pi);

该方法用于设置一次性闹钟,第一个参数表示闹钟类型,第二个参数表示闹钟执行时间,第三个参数表示闹钟响应动作。

(2)setRepeating(int type,long startTime,long intervalTime,PendingIntent pi);

该方法用于设置重复闹钟,第一个参数表示闹钟类型,第二个参数表示闹钟首次执行时间,第三个参数表示闹钟两次执行的间隔时间,第三个参数表示闹钟响应动作。

(3)setInexactRepeating(int type,long startTime,long intervalTime,PendingIntent pi);

该方法也用于设置重复闹钟,与第二个方法相似,不过其两个闹钟执行的间隔时间不是固定的而已。

在项目中用到了第一种和第二种,第三种没有涉及到。

现在先说一下前两种闹钟最基本的用法(摘自于网络),再详细讲述我在项目中遇到的问题和最终是如何解决的。

为了测试的方便直接在Android studio中自动生成activity的oncreate方法里测试了:

一、(1)在指定时长后执行某项操作

代码如下:

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Intent intent =new Intent(this, AlarmReceiver.class);PendingIntent sender= PendingIntent.getBroadcast(this, 0, intent, 0);Calendar calendar= Calendar.getInstance();calendar.setTimeInMillis(System.currentTimeMillis());//将时间设定为系统目前的时间calendar.add(Calendar.SECOND, 5);//系统时间推迟五秒钟,如果为-5,那么就是比系统时间提前五秒钟AlarmManager alarm=(AlarmManager)getSystemService(ALARM_SERVICE);alarm.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), sender);}
}
Toast.makeText(context, "short alarm", Toast.LENGTH_LONG).show();

为了测试的方便我们定义了一个广播接收器,代码如下:

public class AlarmReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {Toast.makeText(context, "short alarm", Toast.LENGTH_LONG).show();}
}

这段代码什么时候执行呢?我们先讲讲在上面activity中用到的令人非常头疼的PendingIntent ,最令人头疼的就是第二个和第四个参数了,暂且定为0( 稍后会讲 )

PendingIntent sender:是闹钟的执行动作,比如发送一个广播、给出提示等等。PendingIntent是Intent的封装类。需要注意的是,如果是通过启动服务来实现闹钟提示的话,PendingIntent对象的获取就应该采用Pending.getService( Context  c,int i,Intent intent,int j)方法;如果是通过广播来实现闹钟提示的话PendingIntent对象的获取就应该采用PendingIntent.getBroadcast(Context c,int i,Intent intent,int j)方法;如果是采用Activity的方式来实现闹钟提示的话,PendingIntent对象的获取就应该采用PendingIntent.getActivity(Context c,int i,Intent intent,int j)方法。如果这三种方法错用了的话,虽然不会报错,但是看不到闹钟提示效果。

从某种意义上来说PendingIntent 其实就是一个延迟的Intent,它将Intent进行了封装,为什么说是延迟呢,是因为当达到某种条件后他才会触发Intent的动作。在本例中就是到运行之后的五秒钟触发Intent的动作,也就是发送一条广播了,提示闹钟设定成功了。至此,上面的例子也就解释的差不多了。顺便把

AlarmManager类型如下:

AlarmManager.RTC,硬件闹钟,不唤醒手机(也可能是其它设备)休眠;当手机休眠时不发射闹钟。

AlarmManager.RTC_WAKEUP,硬件闹钟,当闹钟发射时唤醒手机休眠;

AlarmManager.ELAPSED_REALTIME,真实时间流逝闹钟,不唤醒手机休眠;当手机休眠时不发射闹钟。

AlarmManager.ELAPSED_REALTIME_WAKEUP,真实时间流逝闹钟,当闹钟发射时唤醒手机休眠;
RTC闹钟和ELAPSED_REALTIME最大的差别就是前者可以通过修改手机时间触发闹钟事件,后者要通过真实时间的流逝,即使在休眠状态,时间也会被计算。

(2)周期性的执行某项操作

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Intent intent =new Intent(this, AlarmReceiver.class);PendingIntent sender= PendingIntent.getBroadcast(this, 0, intent, 0);long firstime = SystemClock.elapsedRealtime();AlarmManager am=(AlarmManager)getSystemService(ALARM_SERVICE);//5秒一个周期,不停的发送广播am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, firstime, 5 * 1000, sender);}
}
public class AlarmReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {Toast.makeText(context, "short alarm", Toast.LENGTH_LONG).show();}
}

上面的例子是一个周期性的,每五秒发送一条广播

二、在实际项目中遇到的以下问题及解决办法

项目中有这么一个需求,有很多不同的日程需要不同周期的提醒,如下:

在实际编码中可能你会想到以下的一个循环

        switch (repeatType) {  //repeatType闹钟周期重复的类型case NEVER: //永不AlarmManager manager1 = (AlarmManager) getSystemService(ALARM_SERVICE);Intent intent1 = new Intent(this, AlarmReceiver.class);PendingIntent pi1 = PendingIntent.getBroadcast(this, 0, intent2, 0);manager.set(AlarmManager.RTC_WAKEUP, startTime,intervalTime1 , pi1);break;case EVERY_DAY: //每天AlarmManager manager2 = (AlarmManager) getSystemService(ALARM_SERVICE);Intent intent2 = new Intent(this, AlarmReceiver.class);PendingIntent pi2 = PendingIntent.getBroadcast(this, 0, intent2, 0);manager.setRepeating(AlarmManager.RTC_WAKEUP, startTime,intervalTime2, pi2);//如果当前时间大于了开始时间,则还会提醒了break;case EVERY_WEEK:  //每周AlarmManager manager3 = (AlarmManager) getSystemService(ALARM_SERVICE);Intent intent3 = new Intent(this, AlarmReceiver.class);PendingIntent pi3 = PendingIntent.getBroadcast(this, 0, intent3, 0);manager3.setRepeating(AlarmManager.RTC_WAKEUP,startTime,intervalTime3,pi3);//如果当前时间大于了开始时间,则还会提醒了break;case TWO_WEEK:   //每两周AlarmManager manager4 = (AlarmManager) getSystemService(ALARM_SERVICE);Intent intent4 = new Intent(this, AlarmReceiver.class);PendingIntent pi4 = PendingIntent.getBroadcast(this, 0, intent4, 0);manager4.setRepeating(AlarmManager.RTC_WAKEUP,startTime,intervalTime4,pi4);break;case EVERY_MONTH: //每月AlarmManager manager5 = (AlarmManager) getSystemService(ALARM_SERVICE);Intent intent5 = new Intent(this, AlarmReceiver.class);PendingIntent pi5 = PendingIntent.getBroadcast(this, 0, intent5, 0);manager5.setRepeating(AlarmManager.RTC_WAKEUP,startTime,intervalTime5,pi5);}

上面的intervalTime对应的是间隔时间也就日、周、两周、月…………
这样的思路是没有问题的,但是这样做会出现两个问题:

第一问题:假设现在是八点,你设定的闹钟是七点,那么程序一运行接着就会触发闹钟,这一点需要避免,直接加个判断语句,现在的时间要小于设定时间的时候才能触发闹钟

第二个问题:闹钟的覆盖。Android中的闹钟如果是一样的话,后面的闹钟会覆盖掉前面的闹钟,例如设定了八点和七点的闹钟,那么八点的闹钟会覆盖掉七点的闹钟,最后只会响应一个八点的闹钟。那么怎么区分出不同的闹钟呢,那么就是我们将要讲的 PendingIntent pi = PendingIntent.getBroadcast(this, 0, intent, 0);里面的第二个参数了,这个参数来区分不同的闹钟,我们只需要传进去一个不同的整形值就不再覆盖之前的闹钟了,可以取一个全局变量i,然后这样定义 PendingIntent pi1 = PendingIntent.getBroadcast(this, i++, intent2, 0);,这样就避免了闹钟的覆盖。那么接着问题又来了,我们假设要取消其中的一个周期闹钟,我们应该怎么办呢?

我采用的方法如下

结合上面的讲解,这样定义一个PendingIntent:

  Intent intent = new Intent(this, AlarmReceiver.class);intent.putExtra("alarm_type", ++alarmCount + "");PendingIntent pi = PendingIntent.getBroadcast(this, alarmCount, intent, 0);manager.setRepeating(AlarmManager.RTC_WAKEUP,startTime,intervalTime,pi);

然后当时间到了之后会发送一条广播,我们在广播接收器里取消闹钟,注意和上面的代码对比一下,要取消的是同一个闹钟

public class AlarmReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);PendingIntent pi = PendingIntent.getBroadcast(context, Integer.parseInt(intent.getStringExtra("alarm_type")), intent, 0);manager.cancel(pi);}
}

通过上面的办法就可以取消想要取消的闹钟

后来在结合的代码的时候,主管提出新的要求了:如果两个不同的事件定在同一个时间提醒,如果按照上面的办法会同时弹出两个对话框提醒(因为是两个不同的闹钟),现在要做的就是要合并到一个闹钟,采用列表的形式提醒用户这两个事件到了时间提醒了,也就是一个闹钟。在这个过程中又遇到了一个问题,纠结了我一下午才解决出来,最后只是一个参数的问题,上代码吧:

    private void setAlarmTime(long startTime, ArrayList<Agenda> oneListAgenda) {AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);String[] titleArray = new String[oneListAgenda.size()];for (int i = 0; i < oneListAgenda.size(); i++) {titleArray[i] = oneListAgenda.get(i).getAg_title();}intentReceiver.putExtra("titleArray", titleArray);PendingIntent pi = PendingIntent.getBroadcast(this, alarmCount, intentReceiver,0);manager.set(AlarmManager.RTC_WAKEUP, startTime, pi);}

上面的titleArray数组存着相同时间的日程,这样会出现什么问题呢?

假设设定了一个事件,接着执行了这段代码,接着PendingIntent就会被注册了,如果设定同一个时间的另一个事件,再运行这段代码的时候,这样titleArray里面就是两个值,但是我在广播接收器里取出这个数组的时候,却变成了一个值,究其原因就是PendingIntent 的最后一个参数问题,运行到此处时重新注册一个PendingIntent 就可以了,设置如下:

 PendingIntent pi = PendingIntent.getBroadcast(this, alarmCount, intentReceiver, PendingIntent.FLAG_UPDATE_CURRENT);

上面就是我在项目中遇到的问题,希望对像我一样刚入门的人有所帮助!

Android 闹钟详解相关推荐

  1. Android LayoutInflater详解

    Android LayoutInflater详解 在实际开发中LayoutInflater这个类还是非常有用的,它的作用类 似于findViewById().不同点是LayoutInflater是用来 ...

  2. Android Notification 详解——基本操作

    Android Notification 详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 前几天项目中有用到 Android 通知相关的内容,索性把 Android Notificatio ...

  3. 【转】Android菜单详解——理解android中的Menu--不错

    原文网址:http://www.cnblogs.com/qingblog/archive/2012/06/08/2541709.html 前言 今天看了pro android 3中menu这一章,对A ...

  4. Android菜单详解——理解android中的Menu

    前言 今天看了pro android 3中menu这一章,对Android的整个menu体系有了进一步的了解,故整理下笔记与大家分享. PS:强烈推荐<Pro Android 3>,是我至 ...

  5. android Fragments详解

    android Fragments详解一:概述 android Fragments详解二:创建Fragment 转载于:https://my.oschina.net/liangzhenghui/blo ...

  6. android WebView详解,常见漏洞详解和安全源码(下)

    上篇博客主要分析了 WebView 的详细使用,这篇来分析 WebView 的常见漏洞和使用的坑.  上篇:android WebView详解,常见漏洞详解和安全源码(上)  转载请注明出处:http ...

  7. android WebView详解,常见漏洞详解和安全源码(上)

    这篇博客主要来介绍 WebView 的相关使用方法,常见的几个漏洞,开发中可能遇到的坑和最后解决相应漏洞的源码,以及针对该源码的解析.  由于博客内容长度,这次将分为上下两篇,上篇详解 WebView ...

  8. android子视图无菜单,Android 菜单详解

    Android中菜单分为三种,选项菜单(OptionMenu),上下文菜单(ContextMenu),子菜单(SubMenu) 选项菜单 可以通过两种办法增加选项菜单,一是在menu.xml中添加,该 ...

  9. Android StateFlow详解

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/121913352 本文出自[赵彦军的博客] 文章目录 系列文章 一.冷流还是热流 S ...

最新文章

  1. win7怎么配置程序服务器错误日志文件,win7怎么配置程序服务器
  2. MySQL高级查询语句
  3. win10休眠_win10休眠重新开机黑屏进入不了系统
  4. C#发送Email邮件(实例:QQ邮箱和Gmail邮箱)
  5. wordcloud python3.7_[原创]win7/64位系统+python3.7.2下安装wordcloud库失败之解决——一个莫名其妙的方法...
  6. linux 改变文件夹属性,技术|在Linux中用chattr和lsattr命令管理文件和目录属性
  7. Python的迭代器和生成器
  8. linux 格式化up命令,uptime 命令介绍
  9. linux添加自己的键盘映射,Linux 键盘映射
  10. 网络负载平衡(Network Load Balancing)的工作原理
  11. php算法求出一个数可以被分解成多少个_小学数学必考的34个数学重难点公式,赶紧给孩子收藏!...
  12. 为什么老实人很难当上领导?因为他们身上有这个致命弱点
  13. 应用matlab软件编写 t检验,应用matlab软件进行方差分析 应用方差分析的前提条件...
  14. docker Hub-Node模式运行selenium grid4,经常遇到用例运行到60%-65%时无法继续运行
  15. 搜狐狐友搅局社交;小米手环4发布;2019互联网趋势报告发布;Python火爆依旧...
  16. workflow工作流类型及其区别
  17. vss2005 配置详解
  18. Typora导出word文档自动生成目录
  19. 关于idea中的springboot项目配置maven仓库和插件下载加速
  20. 天下武功唯快不破——实验吧

热门文章

  1. synchronized(this)和synchronized(.class)的理解
  2. NLP 自古以来的各预训练模型 (PTMs) 和预训练任务小结
  3. 七层网络性能基准测试中的协调遗漏问题--Coordinated Omission
  4. PHP中?是什么意思,有什么用?
  5. 数影周报:小米汽车供应商被罚100万,1688延迟下线“1688买家旺旺”
  6. 《操作系统》工作集详解
  7. Python列表实现矩阵的创建、输入输出、转化转置、加减乘运算并设计一个矩阵计算器GUI界面
  8. C语言矩阵运算器,实现矩阵加法、减法、乘法、转置和退出。
  9. 智能扭矩系统——SunTorque智能扭矩系统,引领拧紧工艺新变革!
  10. 清明节网站都变灰了,你知道是怎么做的么?