Android系統提供瞭AlarmManager類來管理鬧鐘定時提醒任務。通過AlarmManager實現定時提醒及定時循環提醒。那麼,AlarmManager類可以應用到以下場景:
1、定時循環啟動組件(Component,如Activity、BroadcastReceiver),這樣能替代在後臺啟動Service進行定時提醒任務
2、實現鬧鐘的按小時、天、周等形式的定時循環提醒功能。
定時啟動組件很簡單,下面貼出鬧鐘按天、周形式的定時循環提醒功能的核心代碼。此功能核心的是計算出下一次鬧鐘提醒時間,代碼如下:
/**
* 鬧鐘三種設置模式(dateMode):
* 1、DATE_MODE_FIX:指定日期,如20120301 , 參數dateValue格式:2012-03-01
* 2、DATE_MODE_WEEK:按星期提醒,如星期一、星期三 , 參數dateValue格式:1,3
* 3、DATE_MODE_MONTH:按月提醒,如3月2、3號,4月2、3號, 參數dateValue格式:3,4|2,3
*
* startTime:為當天開始時間,如上午9點, 參數格式為09:00
*/
public static long getNextAlarmTime(int dateMode, String dateValue,
String startTime) {
final SimpleDateFormat fmt = new SimpleDateFormat();
final Calendar c = Calendar.getInstance();
final long now = System.currentTimeMillis();
// 設置開始時間
try {
if(Task.DATE_MODE_FIX == dateMode) {
fmt.applyPattern("yyyy-MM-dd");
Date d = fmt.parse(dateValue);
c.setTimeInMillis(d.getTime());
}
fmt.applyPattern("HH:mm");
Date d = fmt.parse(startTime);
c.set(Calendar.HOUR_OF_DAY, d.getHours());
c.set(Calendar.MINUTE, d.getMinutes());
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
} catch (Exception e) {
e.printStackTrace();
}
long nextTime = 0;
if (Task.DATE_MODE_FIX == dateMode) { // 按指定日期
nextTime = c.getTimeInMillis();
// 指定日期已過
if (now >= nextTime) nextTime = 0;
} else if (Task.DATE_MODE_WEEK == dateMode) { // 按周
final long[] checkedWeeks = parseDateWeeks(dateValue);
if (null != checkedWeeks) {
for (long week : checkedWeeks) {
c.set(Calendar.DAY_OF_WEEK, (int) (week + 1));
long triggerAtTime = c.getTimeInMillis();
if (triggerAtTime <= now) { // 下周
triggerAtTime += AlarmManager.INTERVAL_DAY * 7;
}
// 保存最近鬧鐘時間
if (0 == nextTime) {
nextTime = triggerAtTime;
} else {
nextTime = Math.min(triggerAtTime, nextTime);
}
}
}
} else if (Task.DATE_MODE_MONTH == dateMode) { // 按月
final long[][] items = parseDateMonthsAndDays(dateValue);
final long[] checkedMonths = items[0];
final long[] checkedDays = items[1];
if (null != checkedDays && null != checkedMonths) {
boolean isAdd = false;
for (long month : checkedMonths) {
c.set(Calendar.MONTH, (int) (month – 1));
for (long day : checkedDays) {
c.set(Calendar.DAY_OF_MONTH, (int) day);
long triggerAtTime = c.getTimeInMillis();
if (triggerAtTime <= now) { // 下一年
c.add(Calendar.YEAR, 1);
triggerAtTime = c.getTimeInMillis();
isAdd = true;
} else {
isAdd = false;
}
if (isAdd) {
c.add(Calendar.YEAR, -1);
}
// 保存最近鬧鐘時間 www.aiwalls.com
if (0 == nextTime) {
nextTime = triggerAtTime;
} else {
nextTime = Math.min(triggerAtTime, nextTime);
}
}
}
}
}
return nextTime;
}
public static long[] parseDateWeeks(String value) {
long[] weeks = null;
try {
final String[] items = value.split(",");
weeks = new long[items.length];
int i = 0;
for (String s : items) {
weeks[i++] = Long.valueOf(s);
}
} catch (Exception e) {
e.printStackTrace();
}
return weeks;
}
public static long[][] parseDateMonthsAndDays(String value) {
long[][] values = new long[2][];
try {
final String[] items = value.split("\\|");
final String[] monthStrs = items[0].split(",");
final String[] dayStrs = items[1].split(",");
values[0] = new long[monthStrs.length];
values[1] = new long[dayStrs.length];
int i = 0;
for (String s : monthStrs) {
values[0][i++] = Long.valueOf(s);
}
i = 0;
for (String s : dayStrs) {
values[1][i++] = Long.valueOf(s);
}
} catch (Exception e) {
e.printStackTrace();
}
return values;
}
如果在鬧鐘響起後,若沒有關閉鬧鐘,還需每隔幾分鐘再次提醒,可以使用AlarmManager的setRepeating()方法,否則使用set()即可。鬧鐘程序還會用到屏幕解鎖相關,具體查看Android屏幕點亮(常亮)及屏幕解鎖和鎖定
摘自 蘿卜白菜的博客