当前位置: 首页 > news >正文

Android学习笔记之AlarmManager有关的定时器和闹钟的实现

  毕业设计中有个功能模块叫就医提醒,大抵的功能就是用户设定一个未来时间的闹钟,并设置闹钟的标签,标签上写着去哪里就医之类的信息,主要设计参考魅族系统自带的闹钟功能。我在网上看了不少博客,也在github上下载了不少源码,发现也没有写的特别好的,总有这种或者那种的问题,比如说闹钟不是写成后台服务的模式,APP关闭之后闹钟不会提醒,或者手机关机之后之前设置的闹钟信息丢失,所以我准备自己写一个功能比较齐全的。

  所以这个闹钟的功能需要用到Android的数据库Sqlite、Service、BroadcastReceiver三大比较重要的模块,之前在看《第一行代码》时,由于看的比较匆忙,所以书本后面的部分知识点学习的并不扎实,书中的代码并没有亲自在IDE中敲一敲,所以借着五一假期三天又重头好好看了一遍《第一行代码》中关于数据库Sqlite、Service、BroadcastReceiver的部分。

  Sqlite是一个轻量级的Android内置数据库,通常只占几百KB的内存,所以在移动设备上也非常的适用。创建数据库的表如下,并写了一个Helper类对数据库操作进行了封装,简化了底层操作数据的操作。

 1 public class AlarmDBHelper extends SQLiteOpenHelper{
 2     public static final String DATABASE_NAME = "userinfo.db";
 3     public static final int DATABASE_VERSION = 2;
 4     public static final String TABLE = "alarm";
 5 
 6 
 7     private static final String CREATE_ALARM_TABLE = "CREATE TABLE " + TABLE + " ("
 8             + AlarmColumn._ID + " integer primary key AUTOINCREMENT,"
 9             + AlarmColumn.ALARM_ID + " text UNIQUE ON CONFLICT REPLACE,"
10             + AlarmColumn.ALARM_CALENDAR + " text,"
11             + AlarmColumn.ALARM_CANCELABLE + " text,"
12             + AlarmColumn.ALARM_TAG + " text,"
13             + AlarmColumn.ALARM_AVAILABLE + " text,"
14             + AlarmColumn.ALARM_RINGTONE + " text)";
15 
16     public AlarmDBHelper(Context context) {
17         super(context, DATABASE_NAME, null, DATABASE_VERSION);
18     }
19 
20     @Override
21     public void onCreate(SQLiteDatabase db) {
22         db.execSQL(CREATE_ALARM_TABLE);
23     }
24 
25     @Override
26     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
27         String sql=" DROP TABLE IF EXISTS "+TABLE;
28         db.execSQL(sql);
29         onCreate(db);
30     }
31 }

若要修改原先的数据库,只需要在 dbHelper = new AlarmDBHelper(this, "userinfo.db", null, 3); 中增加version的版本号即可。数据库的操作无非就是CRUD,C代表添加(Create),R代表查询(Retrieve),U代表更新(Update),D代表删除(Delete)。操作基本与SQL相同,同时官方支持使用SQL语句建立数据库和CRUD。其中查询数据库设计到一个新的数据类型——Cursor,本意为光标,可以理解为数据库中每行的内容。cursor.moveToFirst()移动到表中的第一行,cursor.moveToNext() 即指移动到下一行。上述代码即创建一个闹钟的 table ,将创建闹钟所需的一些信息保存在数据库中。

 1 public class BootReceiver extends BroadcastReceiver{
 2     @Override
 3     public void onReceive(Context context, Intent intent) {
 4         ArrayList<Alarm> alarms = getAllAlarms(context);
 5         for (Alarm alarm : alarms) {
 6             // Test
 7             // 当重启后,所有的都应该恢复,而如果这是定时任务,那么只要恢复月度和年度的就可以了.
 8             // 如果每天00:00重建闹钟的话,那么00:00时响的闹钟会不会响呢
 9             // 所以最后错开一点,因为闹钟没有秒数,所以设置为00:00:30秒何如。
10             // 不论是什么闹钟,都会保证如果第二天有闹钟的话就会设置上的,所以不用担心00:00的闹钟不会设置上
11             alarm.activate();
12         }
13     }
14 
15     /**
16      * 从本地数据库恢复所有的闹钟
17      *
18      * @return
19      */
20     private ArrayList<Alarm> getAllAlarms(Context context) {
21         AlarmHelper helper = new AlarmHelper(context);
22         return helper.getAlarms();
23     }
24 }

并注册一个广播监听开机的action,每当开机时将所有的alarm从数据库中都出来,并激活所有的闹钟,即AlarmReceive监听所有闹钟。

 1  private void setOneTimeAlarm() {
 2         if (AudreyCalendar.getTimeInMillis() - System.currentTimeMillis() > 0) {
 3             // 最后一个参数必须是PendingIntent.FLAG_UPDATE_CURRENT,否则BroadcastReceiver将收不到参数。
 4             PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext,
 5                     0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
 6             AlarmManager manager = (AlarmManager) mContext
 7                     .getSystemService(Context.ALARM_SERVICE);
 8             manager.set(AlarmManager.RTC_WAKEUP,
 9                     AudreyCalendar.getTimeInMillis(), pendingIntent);
10         } else {
11             Toast.makeText(mContext, "小伙子,设置太早闹钟是不会执行滴!",
12                     Toast.LENGTH_SHORT).show();
13         }
14     }

通过这样数据库中的闹钟会在 setOneTimeAlarm() 设置响铃的时间。AlarmReceive 中的代码如下,

 1 public class AlarmReceiver extends BroadcastReceiver{
 2 
 3     @Override
 4     public void onReceive(Context context, Intent intent) {
 5 
 6         Alarm alarm=new Alarm(context, intent.getExtras());
 7         Intent intent2=new Intent();
 8         intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 9         intent2.setClass(context, RingActivity.class);
10         intent2.putExtras(Alarm.alarm2Bundle(alarm));
11         context.startActivity(intent2);
12 
13 
14 
15     }
16 }

通过Receive中的方法启动RingActivity,触发响铃的操作,整个闹钟的逻辑就完成了。

按理说,闹钟的实现应该通过service实现,这样就可以使得即使app关闭时,后台的闹钟也是在运行的,不过如何在service中启动一个闹钟我不知道如何实现。整个的逻辑应该是当设置好闹钟的属性,点击增加闹钟时,闹钟的信息被保存在数据库中,同时触发一个service启动,在service服务中接受alarm中的信息,设置后一个

 PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext,
 5                     0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
 6             AlarmManager manager = (AlarmManager) mContext
 7                     .getSystemService(Context.ALARM_SERVICE);
 8             manager.set(AlarmManager.RTC_WAKEUP,
 9  AudreyCalendar.getTimeInMillis(), pendingIntent); 将getBroadcast改成getActivity,跳转到RingActivity即可实现整个的逻辑。


因我的代码借鉴了他人的代码,导致我在代码的阅读中陷入了极大的混乱,同时整个的逻辑也非常的不清晰,造成了代码工作非常缓慢的事实,此后我必须在阅读他人的代码的基础上理解整个逻辑实现,理清思路,完成自己的设计。

 

转载于:https://www.cnblogs.com/fengmanlou/p/4477997.html

相关文章:

  • oozie 安装过程总结
  • Ossim中查看网络流量历史数据
  • linux下安装FFmpeg
  • XML处理类
  • Prototype属性
  • Modeless对话框如何响应快捷键
  • C# UDP(Socket)异步传输文件
  • leetcode 155 Min Stack
  • spring冲刺第二天
  • [转]太阳致敬式瑜伽
  • Linux环境Weblogic10g服务部署
  • ExecutorService生命周期(转)
  • Solr使用入门指南
  • 关于统计信息过期的性能落差
  • 线段树(单点更新)/树状数组 HDOJ 1166 敌兵布阵
  • [case10]使用RSQL实现端到端的动态查询
  • 2018以太坊智能合约编程语言solidity的最佳IDEs
  • conda常用的命令
  • IOS评论框不贴底(ios12新bug)
  • Javascripit类型转换比较那点事儿,双等号(==)
  • JavaScript类型识别
  • js继承的实现方法
  • nodejs实现webservice问题总结
  • opencv python Meanshift 和 Camshift
  • React as a UI Runtime(五、列表)
  • Spark VS Hadoop:两大大数据分析系统深度解读
  • vue+element后台管理系统,从后端获取路由表,并正常渲染
  • 阿里云ubuntu14.04 Nginx反向代理Nodejs
  • 纯 javascript 半自动式下滑一定高度,导航栏固定
  • 从 Android Sample ApiDemos 中学习 android.animation API 的用法
  • 警报:线上事故之CountDownLatch的威力
  • 来,膜拜下android roadmap,强大的执行力
  • 浅谈Kotlin实战篇之自定义View图片圆角简单应用(一)
  • 如何选择开源的机器学习框架?
  • 首页查询功能的一次实现过程
  • 验证码识别技术——15分钟带你突破各种复杂不定长验证码
  • 在 Chrome DevTools 中调试 JavaScript 入门
  • 400多位云计算专家和开发者,加入了同一个组织 ...
  • CMake 入门1/5:基于阿里云 ECS搭建体验环境
  • ​油烟净化器电源安全,保障健康餐饮生活
  • # .NET Framework中使用命名管道进行进程间通信
  • #大学#套接字
  • #免费 苹果M系芯片Macbook电脑MacOS使用Bash脚本写入(读写)NTFS硬盘教程
  • $GOPATH/go.mod exists but should not goland
  • (145)光线追踪距离场柔和阴影
  • (附源码)ssm航空客运订票系统 毕业设计 141612
  • (十一)手动添加用户和文件的特殊权限
  • (五)IO流之ByteArrayInput/OutputStream
  • (一)Neo4j下载安装以及初次使用
  • (已解决)报错:Could not load the Qt platform plugin “xcb“
  • *(长期更新)软考网络工程师学习笔记——Section 22 无线局域网
  • ***详解账号泄露:全球约1亿用户已泄露
  • *1 计算机基础和操作系统基础及几大协议
  • .net core IResultFilter 的 OnResultExecuted和OnResultExecuting的区别
  • .NET 中小心嵌套等待的 Task,它可能会耗尽你线程池的现有资源,出现类似死锁的情况