Android时钟应用的定时框架分析

Android系统闹钟定时功能框架,总体来说就是用数据库存储定时数据,有一个状态管理器来统一管理这些定时状态的触发和更新。在Andriod系统中实现定时功能,最终还是要用到系统提供的AlarmManager,只是当一个定时完成后怎么继续处理,或者中间怎么更新定时的时间或者状态,像闹钟这种应用程序,每天重复定时,或者一周选择其中的几天,闹钟响了延迟5分钟再次响铃,这时候就需要想一种好的办法来让管理这些数据和状态,下面就分析一下Android系统闹钟的实现。

1、基本结构

Alarm

代表一条定时数据

AlarmInstance

代表一个定时项目的实例,一个AlarmInstance对应到一个Alarm,相比Alarm多存储了一些状态信息

AlarmStateManager

状态管理器,对定时项目进行调度,添加、删除、更改状态,是一个BroadcastReciever,定时到点后发广播到这里进行下一步处理

AlarmService

响应结果,也就是定时到达后要做的事,,响铃,停止响铃

ClockDataHelper

里面创建了三个表,ALARMS_TABLE,INSTANCE_TABLE,CITIES_TABLE,前两个分别对应到上面的Alarm和AlarmInstance。

private static void createAlarmsTable(SQLiteDatabase db) {db.execSQL("CREATE TABLE " + ALARMS_TABLE_NAME + " (" +ClockContract.AlarmsColumns._ID + " INTEGER PRIMARY KEY," +ClockContract.AlarmsColumns.HOUR + " INTEGER NOT NULL, " +ClockContract.AlarmsColumns.MINUTES + " INTEGER NOT NULL, " +ClockContract.AlarmsColumns.DAYS_OF_WEEK + " INTEGER NOT NULL, " +ClockContract.AlarmsColumns.ENABLED + " INTEGER NOT NULL, " +ClockContract.AlarmsColumns.VIBRATE + " INTEGER NOT NULL, " +ClockContract.AlarmsColumns.LABEL + " TEXT NOT NULL, " +ClockContract.AlarmsColumns.RINGTONE + " TEXT, " +ClockContract.AlarmsColumns.DELETE_AFTER_USE + " INTEGER NOT NULL DEFAULT 0);");Log.i("Alarms Table created");} private static void createInstanceTable(SQLiteDatabase db) {db.execSQL("CREATE TABLE " + INSTANCES_TABLE_NAME + " (" +ClockContract.InstancesColumns._ID + " INTEGER PRIMARY KEY," +ClockContract.InstancesColumns.YEAR + " INTEGER NOT NULL, " +ClockContract.InstancesColumns.MONTH + " INTEGER NOT NULL, " +ClockContract.InstancesColumns.DAY + " INTEGER NOT NULL, " +ClockContract.InstancesColumns.HOUR + " INTEGER NOT NULL, " +ClockContract.InstancesColumns.MINUTES + " INTEGER NOT NULL, " +ClockContract.InstancesColumns.VIBRATE + " INTEGER NOT NULL, " +ClockContract.InstancesColumns.LABEL + " TEXT NOT NULL, " +ClockContract.InstancesColumns.RINGTONE + " TEXT, " +ClockContract.InstancesColumns.ALARM_STATE + " INTEGER NOT NULL, " +ClockContract.InstancesColumns.ALARM_ID + " INTEGER REFERENCES " +ALARMS_TABLE_NAME + "(" + ClockContract.AlarmsColumns._ID + ") " +"ON UPDATE CASCADE ON DELETE CASCADE" +");");Log.i("Instance table created");}

这里说一下几个特殊的字段,对于Alarm表,DAYS_OF_WEEK表示一周内需要定时的天(闹钟有个功能是选择一周中的几天),这里是个int值,用位来表示设置的天数,源码中有个专门的类DaysOfWeek来存储和处理。

AlarmInstance表中有一个ALARM_ID,关联到一个Alarm,可以看到在AlarmInstance表里也有时间,为什么不和Alarm表合成一个表?应该是这样的,Alarm表示原始的定时项,是一个基础数据,而AlarmInstance则代表了一个使用中的定时项目,或者是一个已经激活的定时项目,它的时间是可以变化的,比如闹钟响了以后延时5分钟再响,就需要改变这里的时间,而基础数据不能变,还需要显示在那里。ALARM_STATE代表了当前定时项目的状态,具体调度都在AlarmStateManager中管理。

忘了在哪里看到的,“编程最重要的是设计数据结构,接下来是分解各种代码块”。数据结构是基础,就像建筑里的钢筋水泥砖瓦,有了基础的材料后,剩下的工作就是对这些材料处理,也就是设计具体的处理逻辑。

2、具体的类分析

Alarm

从上面也可以看出,Alarm类作为定时的基础数据结构,主要是封装了一些数据库操作,完成增删改查功能。额外有一个方法createInstanceAfter,根据自身来创建一个AlarmInstance实例。代码如下

public AlarmInstance createInstanceAfter(Calendar time) {Calendar nextInstanceTime = Calendar.getInstance();nextInstanceTime.set(Calendar.YEAR, time.get(Calendar.YEAR));nextInstanceTime.set(Calendar.MONTH, time.get(Calendar.MONTH));nextInstanceTime.set(Calendar.DAY_OF_MONTH, time.get(Calendar.DAY_OF_MONTH));nextInstanceTime.set(Calendar.HOUR_OF_DAY, hour);nextInstanceTime.set(Calendar.MINUTE, minutes);nextInstanceTime.set(Calendar.SECOND, 0);nextInstanceTime.set(Calendar.MILLISECOND, 0);// If we are still behind the passed in time, then add a dayif (nextInstanceTime.getTimeInMillis() <= time.getTimeInMillis()) {nextInstanceTime.add(Calendar.DAY_OF_YEAR, 1);}// The day of the week might be invalid, so find next valid oneint addDays = daysOfWeek.calculateDaysToNextAlarm(nextInstanceTime);if (addDays > 0) {nextInstanceTime.add(Calendar.DAY_OF_WEEK, addDays);}AlarmInstance result = new AlarmInstance(nextInstanceTime, id);result.mVibrate = vibrate;result.mLabel = label;result.mRingtone = alert;return result;}AlarmInstance忍耐力较诸脑力,尤胜一筹。

Android时钟应用的定时框架分析

相关文章:

你感兴趣的文章:

标签云: