安排重复的基于时间的警报

Scheduling repeated time-based alarms

我想安排多个重复的基于时间的闹钟。根据this android dev doc,"Repeating alarms that are based on a precise trigger time don't scale well",这是为什么,我不明白。但我需要这种精确的功能。那么我有什么选择呢?我的主要目标是使用 AlarmManager class 安排警报,并在安排的时间到来时发出通知,但考虑到开发文档,我不太确定如何去做。

编辑:

我设法安排了我的闹钟,从严格意义上讲,它不是在设定的时间间隔后重复出现的完全重复的基于时间的闹钟,但 "repeating" 在设置多个闹钟的意义上。现在,当我在日历上设置日期和时间时,月份会提前一个月设置,如果我输入 10,它会将月份设置为 11,这是我的代码:

Calendar cal = Calendar.getInstance();
String date = "23/10/2016";//month set to 10
String[] _date = date.split("/");
String time = "4:33";
String[] _time = time.split(":");

Intent intent = new Intent(test.this,
            AlarmReceiver.class);


intent.setData(Uri.parse("timer:555"));

PendingIntent sender = PendingIntent.getBroadcast(
            test.this, 0, intent,
            0);

cal.set(Integer.parseInt(_date[2]), //year
        Integer.parseInt(_date[1]), //month
        Integer.parseInt(_date[0]), //day
        Integer.parseInt(_time[0]), //hour
        Integer.parseInt(_time[1]));//minute

AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender);

Toast mToast = Toast.makeText(
            test.this,
            "Reminders added to the calendar successfully for "
                    + android.text.format.DateFormat.format(
                    "MM/dd/yy h:mmaa",
                    cal.getTimeInMillis()),
            Toast.LENGTH_LONG);
mToast.show();//month displayed is 11

我正在使用 AlarmManager 就像你想在我的项目中做的那样。在项目中,我可以安排单次或每天、每周、每月、每年的警报。实际上它工作正常,但 OS 可以改变电池效率的警报,有时可能会延迟 1 分钟。如果您在 AlarmManager.html#setRepeating 中阅读此内容:

Note: as of API 19, all repeating alarms are inexact. If your application needs precise delivery times then it must use one-time exact alarms, rescheduling each time as described above. Legacy applications whose targetSdkVersion is earlier than API 19 will continue to have all of their alarms, including repeating alarms, treated as exact.

如果您阅读了其中接受的答案,您就会明白:alarmmanager-fires-alarms-at-wrong-time

请也阅读这个选定的答案:alarmmanager-setexact-with-wakefulbroadcastreceiver-sometimes-not-exact

如果您想知道我在使用哪个:我正在使用不精确警报,因为我不想消耗电池,因为时间在我的应用程序中并不重要。

请注意;不精确的警报更省电。如果时间对您来说不重要,请改用 inexact。

最后,如果您想查看一些代码示例,我在 Bitbucket 中有历史记录。我可以给你我现有的代码供你参考,或者如果你用你的尝试更新你的问题,我可以指导你。

@为 setExact 编辑:

首先你必须这样声明你的闹钟:

Intent alarmIntent = new Intent(getApplicationContext(), YourAlarmReceiver.class);
//this is important for you you must store this value
// you need this request code when shifting your Alarms
int piRequstCode=(int) System.currentTimeMillis();

对于简单的方法,您可以存储待处理的意向请求代码,例如:

alarmIntent.putExtra("piRequestCode",piRequstCode);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(),piRequstCode,alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
//use mCalendarNotification to set your date for trigger
alarmManager.setExact(AlarmManager.RTC_WAKEUP, mCalendarNotification.getTimeInMillis(), pendingIntent);

然后在你的 BroadcastReceiver 中:

@Override
public void onReceive(Context context, Intent intent) {
   //right now you have your intent and context, so you can shift your alarm
   Bundle extras=intent.getExtras();
   int piRequestCode=extras.getInt("piRequestCode");
   Intent alarmIntent=new Intent(context, YourAlarmReceiver.class);
   alarmIntent.putExtra("piRequestCode",piRequstCode);

   // this will return your existing pending intent because your Intent and request code is same 
   // and FLAG_UPDATE_CURRENT updates pendingIntent with new config. 
   // If there is no pending Intent that matches with this requestCode and intent it will create new one.
   PendingIntent pendingIntent = PendingIntent.getBroadcast(context,piRequestCode,alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);

   //use AlarmManager with context
   AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
   alarmManager.setExact(AlarmManager.RTC_WAKEUP,shiftedTime, pendingIntent);
}

还有一件事,当设备重新启动时,所有警报都将丢失。并且您必须手动重置警报。因此,将 pendingIntent 请求代码存储在数据库中(SqliteRealm 等...)或 SharedPreferences(如果您没有太多数据)是一个很好的策略。现在我正在使用 Realm 来存储 requestCodes 和所有其他东西,所以我建议你使用数据库。

如果您在执行此步骤时需要更多帮助,请在最后明确说明,创建新问题或编辑此问题,我会帮助您。