Android鬧鐘程序周期循環提醒源碼(AlarmManager)

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屏幕點亮(常亮)及屏幕解鎖和鎖定

 

摘自 蘿卜白菜的博客

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。