【问题标题】:AlarmManager triggers PendingIntent too soonAlarmManager 过早触发 PendingIntent
【发布时间】:2012-06-02 20:26:34
【问题描述】:

我已经搜索了 3 天,但在其他任何地方都没有找到解决方案或类似的问题/问题。这是交易:

1 小时内触发 -> 正常工作

2 小时后触发 -> 1:23 结束

1 天内触发 -> 约 11:00 结束

那么为什么 AlarmManager 如此不可预测且总是太快?或者我做错了什么?还有其他方法可以正常工作吗?

这是我在 AlarmManager 中注册 PendingIntent 的方式(精简):

AlarmManager alarmManager = (AlarmManager)parent.getSystemService(ALARM_SERVICE);
Intent myIntent = new Intent(parent, UpdateKlasRoostersService.class);
PendingIntent pendingIntent = PendingIntent.getService(parent, 0, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);

//Set startdate of PendingIntent so it triggers in 10 minutes
Calendar start = Calendar.getInstance();
start.setTimeInMillis(SystemClock.elapsedRealtime());
start.add(Calendar.MINUTE, 10);

//Set interval of PendingIntent so it triggers every day
Integer interval = 1*24*60*60*1000;

//Cancel any similar instances of this PendingIntent if already scheduled
alarmManager.cancel(pendingIntent);

//Schedule PendingIntent
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, start.getTimeInMillis(), interval, pendingIntent);
//Old way I used to schedule a PendingIntent, didn't seem to work either
//alarmManager.set(AlarmManager.RTC_WAKEUP, start.getTimeInMillis(), pendingIntent);

如果有人有解决方案,那就太棒了。感谢您的帮助!

更新: 2 小时前它以 2 小时的间隔触发它,但之后它在 1:20 小时后触发。它变得非常奇怪。我将使用日志文件跟踪触发器并在明天将其发布在这里。

更新: PendingIntent 计划每 3 小时运行一次。从日志的第二行看来,旧的预定 PendingIntent 仍在运行:

[2012-5-3 2:15:42 519] Updating Klasroosters
[2012-5-3 4:15:15 562] Updating Klasroosters
[2012-5-3 5:15:42 749] Updating Klasroosters
[2012-5-3 8:15:42 754] Updating Klasroosters
[2012-5-3 11:15:42 522] Updating Klasroosters

但是,我确定我在安排新的 PendingIntent 之前取消了预定的 PendingIntent。并且每个 PendingIntent 都不会以相同的方式重新创建,因此它应该完全相同。如果不是,则此线程问题不再相关。

【问题讨论】:

  • 我无法重现您的问题。究竟如何将start 更改为提前 2 小时,也可以提前 1 天?
  • 我添加了日志文件,发现可能旧的 PendingIntent 仍在运行。
  • 我也遇到了同样的问题,请问您有解决办法吗?

标签: android alarmmanager android-pendingintent


【解决方案1】:

在使用日历时,您是否考虑到日历使用的时间精确到毫秒。也许您应该将 Milli second 字段和 seconds 字段设置为零,这样它就可以开始了。

还有一天用这个会更方便

Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(0);
cal.add(Calendar.DAY_OF_MONTH, 1);

此外,当您使用 getInstance 时,不会将日历时间设置为创建时间,因此不需要再次设置时间,对吧?

【讨论】:

  • 查看文档, SystemClock.elapsedRealtime() 是手机启动后的时间,而不是实际时间。此外,我不认为 setTimeInMillis(0) 调用是必要的,因为您希望从现在开始 1 天发出警报,而不是从纪元(很久以前)开始的 1 天。
  • 但我相信他使用 1 天作为间隔而不是实际时间?
  • 是的,但我假设这个问题与使用Calendar 设置的触发时间有关。 1 天的间隔是使用Integer 定义的,应该没问题。
  • 因为我在手机启动后重新安排了 PendingIntent,所以使用 SystemClock.elapsedRealtime() 不会有问题。让它独立于手机空闲和活动时间会更好,但我认为这不会有任何伤害。我将记录触发器并在明天报告。
  • elapsedRealtime() 以系统启动后的毫秒数为单位,包括深度睡眠。
【解决方案2】:

重写:我最终看到了你的错误,但出乎意料。

我确实改变了这个:

PendingIntent.getService(parent, 0, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);

到这里:

PendingIntent.getService(parent, 0, myIntent, PendingIntent.FLAG_CANCEL_CURRENT);

在与您相同的假设下,以某种方式旧意图正在广播。从那以后我就再也没有看到过侥幸……

我唯一一次看到它是在我第一次打电话的时候。另一种方法可能是跟踪current 和previous 日历对象,如果间隔不是您所期望的,则忽略此“早期”广播。 (虽然考虑到警报 应该 的工作方式,这种方法似乎是多余的,但考虑到警报 的工作方式,它有助于防止那些无关的调用......)

希望对您有所帮助,如果我找到其他任何东西,我会告诉您。

【讨论】:

  • 感谢您的努力,但我已经这样做了。当我分析这些数据时,它应该会按时触发 PendingIntent,但事实并非如此。所以,这就是问题所在。
  • 很抱歉听到这个消息......当你发布新数据时标记我,如果可以的话我会提供帮助。
  • @Wezelkrozum 我添加了一个可能的答案。
【解决方案3】:

我知道这个问题有点老了,但我自己也遇到了同样的问题。我发现如果我试图在方法之外声明 Calendar 变量,它不会很好地发挥作用,并且警报会提前触发。因为你的类被剥离了,所以很难准确地说出你在哪里调用日历实例。

如果我这样设置,它会准时触发:

protected void nextAlarm(Context context, int seconds){
    Calendar nextAlarm = Calendar.getInstance();

    Intent intent = new Intent(context, MyClass.class);
    PendingIntent pending = PendingIntent.getBroadcast(context, MainActivity.REPEATING_ALARM, intent, PendingIntent.FLAG_CANCEL_CURRENT);

    AlarmManager amanager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
    nextAlarm.add(Calendar.SECOND, seconds);

    amanager.set(AlarmManager.RTC_WAKEUP, nextAlarm.getTimeInMillis(), pending);

}

【讨论】:

  • 老实说,这不是解决办法。我在方法中创建日历。但我确实看到我们检索 PendingIntent 的方式有所不同。你使用 getBroadcast 方法,而我使用 getService 方法。
【解决方案4】:

确保你的服务的onStartCommand返回START_NOT_STICKY,否则会自动重试:

public class UpdateKlasRoostersService extends Service {
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        buildUpdate();
        return START_NOT_STICKY;
    }
}

【讨论】:

  • 这是否意味着我的服务一直在尝试启动?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多