AlarmManager触发PendingIntent太早

6
我已经搜索了三天,但没有找到任何解决方案或类似的问题/问题。以下是要处理的问题:
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小时的间隔触发它是有效的,但之后它在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并不是以相同的方式重新创建的,因此应该完全相同。如果不是这样,那么这个线程的问题就不再相关。


1
我无法重现你的问题。请问您如何更改start以使其向前推进2小时和1天? - Sam
1
我添加了日志文件并发现可能仍在运行旧的PendingIntent。 - Wezelkrozum
我也有同样的问题,你有可行的解决方案吗? - david
4个回答

1

在使用日历时,您是否考虑到日历使用时间精确到毫秒。也许您应该将毫秒字段和秒字段设置为零,以便准时进行。

另外,对于一天的计算,使用这个方法会更容易。

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

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


1
在文档中查找,SystemClock.elapsedRealtime()是自手机启动以来的时间,而不是实际时间。此外,我认为setTimeInMillis(0)调用是不必要的,因为你想要从现在开始1天后响起闹钟,而不是从纪元开始(那时已经很久远了)。 - Alex Curran
1
但我相信他使用的是1天作为间隔而不是实际时间? - FabianCook
1
是的,但我假设这个问题出在触发时间上,它是使用“日历”设置的。1天间隔是使用“整数”定义的,应该没问题。 - Alex Curran
2
由于我在手机启动后重新安排了PendingIntent,因此使用SystemClock.elapsedRealtime()不会有问题。让它与手机的空闲和活动时间无关可能更好,但我认为这不会有任何影响。我将记录触发器并明天回报。 - Wezelkrozum
1
elapsedRealtime()是自系统启动以来以毫秒为单位计算的时间,包括深度睡眠时间。 - Andrey Ermakov

1
我知道这个问题有点老,但我自己也遇到了同样的问题。我发现如果我试图在方法外声明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);

}

1
说实话,我觉得这不是修复的方法。我会在方法内创建日历。但是我确实看到了我们获取PendingIntent的方式有所不同。你使用getBroadcast方法,而我使用getService方法。 - Wezelkrozum

1
确保您的服务的onStartCommand返回START_NOT_STICKY,否则它将自动重新尝试:
public class UpdateKlasRoostersService extends Service {
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        buildUpdate();
        return START_NOT_STICKY;
    }
}

1
这是否意味着我的服务一直在尝试启动? - Wezelkrozum

1

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

我已经更改了这个:

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

转换为:

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

在你的假设下,某种方式一个旧意图正在广播。自从那以后我就再也没有看到过这个巧合...

此外,我只在最初的呼叫时看到过它。另一种方法是跟踪当前之前的日历对象,如果间隔不是你期望的,则忽略这个“早期”广播。(虽然这种方法似乎是多余的,考虑到闹钟应该如何工作,但它有助于防止那些额外的调用,考虑到闹钟正在工作...)

希望这有所帮助,如果我发现其他信息,我会告诉你。


1
谢谢你的努力,但我已经完成了这个任务。当我分析这些数据时,应该能够准时触发PendingIntent,但是它没有触发。所以,这就是问题所在。 - Wezelkrozum
1
很遗憾听到这个消息...在发布新数据时标记我,如果可以的话,我会提供帮助。 - Sam
1
@Wezelkrozum 我添加了一个可能的答案。 - Sam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接