【问题标题】:AlarmManager fires at different timesAlarmManager 在不同的时间触发
【发布时间】:2014-09-13 17:38:22
【问题描述】:

我已创建并部署到 Google Play 警报应用程序。与往常一样,我在 8 个不同的真实设备(我不使用模拟器)上进行了大量测试,这些设备运行不同的 api 级别、root/non-root、不同的时区以及其他功能。

问题在于,在下载量超过 10,000 次后,一些用户抱怨警报在指定时间前 1 小时触发,而其他一些用户(4 倍数量)则抱怨警报在 1 小时后触发。我从世界上不同的地方得到这个,我也从同一个地方得到 5 星。 瞬间我以为我在代码的某些地方错误地使用了时区,但事实是我只是在使用

GregorianCalendar gc = new GregorianCalendar();

我在所有代码中都使用了这种实例化。我使用系统 AlarmManager 设置警报,例如:

    AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(context.getApplicationContext(), AlarmReceiver.class);
    GregorianCalendar gc = new GregorianCalendar();
    long triggerAtMillis = 0;
    if(nextAlarm != null){
        triggerAtMillis = System.currentTimeMillis() 
                + 60*1000*alarmDifference(nextAlarm, gc.get(Calendar.HOUR_OF_DAY), gc.get(Calendar.MINUTE), true)
                - 1000*gc.get(Calendar.SECOND);

    }else{
//          Log.d("", "nextAlarm: NULL");
    return;
    }

    PendingIntent operation = PendingIntent.getBroadcast(context.getApplicationContext(), REQUEST_CODE_ALARM_BROADCAST, intent, 0);
    am.set(AlarmManager.RTC_WAKEUP, triggerAtMillis, operation);

alarmDifference 方法很简单:

public static int alarmDifference(Alarm alarm, int hour, int minute, boolean inverse) {
    int hours = hour - alarm.getHour();
    if(inverse){
        hours *= -1;
    }
    if(hours < 0)
        hours += 24;

    int minutes = minute - alarm.getMinute();
    if(inverse){
        minutes *= -1;
    }

    if(hours==0 && minutes<0){
        hours = 23; //this happens if we set the time to the current hour
    }

    if(minutes < 0)
        minutes += 60;

//  Log.d("", "Time left: "+ hours+" hours, " + minutes+" minutes");
    return hours*60 + minutes;

}

我的目标是 api 级别 17,所以我不会遇到系统不遵守交货时间的问题,并且必须使用 AlarmManager.setExact(...)

要唤醒我的服务,我使用的是 WakefulBroadcastReceiver,因此我不必自己处理 WakeLock。

我在该网站上进行了大量研究,并尝试了不同的方法,但没有任何运气。

提前致谢。

【问题讨论】:

  • 你在检查上午和下午吗?
  • 请注意我正在使用 Calendar.HOUR_OF_DAY 的代码;那是 24 小时制,所以我不需要检查上午/下午。

标签: android alarmmanager


【解决方案1】:

你可以尝试使用next来查找问题:

在您的应用程序中从互联网服务(例如,http://developer.yahooapis.com/TimeService/V1/getTime?appid=YahooDemo)加载世界时间,并将时间与设备上的时区进行比较。您可以确定问题所在:全局设备中或您的应用中。

【讨论】:

  • 应用程序应该离线工作,所以这是无效的。无论如何,谢谢。
  • 您也可以尝试使用来自 GPS (NMEA) 数据的比较时间(这个时间并不总是正确的)。这不需要互联网许可,但需要位置许可。
  • 这种方式有更多的缺点,因为用户可能禁用了位置,或者在一段时间内没有获得位置更新。行不通。
【解决方案2】:

我很确定问题出在这一行:

triggerAtMillis = System.currentTimeMillis() 
                + 60*1000*alarmDifference(nextAlarm, gc.get(Calendar.HOUR_OF_DAY), gc.get(Calendar.MINUTE), true)
                - 1000*gc.get(Calendar.SECOND);

此操作保证自动发生。换句话说,

  • gc.get(Calendar.HOUR_OF_DAY)
  • gc.get(Calendar.MINUTE)

可能发生在不同的时间,例如当时钟从 14:59:99 变为 15:00:00 时,您可能会得到 14 小时和 00 分钟,或者 15 小时和 59 分钟

相反,我会从不可变的时间戳值中提取小时/分钟/秒。

【讨论】:

  • 我会试试这个,但根据谷歌分析,用户没有将时间设置为 XX:59,也不是 XX:00。我会告诉你的。
  • GregorianCalendar 对象 gc 在实例化后不会改变,因此它是不可变的。警报差异是使用 POJO 的自定义警报对象计算的,因此 triggerAtMillis 值不会在系统时间发生变化时发生变化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多