Android set()和setExact()以不正确的间隔触发警报

时间:2015-05-10 07:57:13

标签: java android alarmmanager

我正在开发一款应该每60秒执行一次任务的应用。由于Android 4.4+中的警报存在一些准确性问题,其中所有警报都不准确,我选择了链式模型:A BroadcastReceiver触发第一个警报,每个警报依次设置下一个警报。

问题在于,即使我以60秒(60000毫秒)的间隔设置警报,警报也会以5秒的间隔触发,有时甚至更短。我已经在我的Nexus 5(Android 5.1.1)和Android 5.0.1仿真器上测试了代码,两者都给出了相同的结果。 我应该指出,两个接收器都在AndroidManifest上注册,我的应用程序具有RECEIVE_BOOT_COMPLETED权限。

编辑:setExact()导致完全相同的问题

StartupReceiver.java (BroadcastReceiver for BOOT_COMPLETED):

public class StartupReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "Got the BOOT_COMPLETED signal");
        // Get the first alarm to be invoked immediately
        AlarmReceiver.setNextScanAlarm(context, 0);
    }
}

AlarmReceiver.java

public class AlarmReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // Start the service
        Intent startServiceIntent = new Intent(context, BackgroundService.class);
        startServiceIntent.putExtra("interval", 60000);
        startServiceIntent.putExtra("action", "scan");
        context.startService(startServiceIntent);

        // Schedule the next alarm
        setNextScanAlarm(context, 60000);
    }

    public static void setNextScanAlarm(Context context, int interval) {
        Intent scanIntent = new Intent(context, AlarmReceiver.class);
        scanIntent.putExtra("interval", interval);
        scanIntent.putExtra("action", "scan");
        PendingIntent pendingIntent = PendingIntent.getBroadcast(
                context,
                0,
                scanIntent,
                PendingIntent.FLAG_ONE_SHOT);


        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        alarmManager.set(
                AlarmManager.ELAPSED_REALTIME_WAKEUP,
                interval,
                pendingIntent);
    }
}

可能是什么问题?

2 个答案:

答案 0 :(得分:0)

我相信因为这是一个叫闹钟

alarmManager.set(
                AlarmManager.ELAPSED_REALTIME_WAKEUP,
                interval,
                pendingIntent);

您正在调用的变量interval是您希望在下一次警报之前经过的时间,但是当您考虑这个时,它何时知道要启动?更重要的是,什么时间实际上等于零?

当你创造它?没有。
当你致电.set()时? No.
在BOOT上实际上是零。所以你要求它在启动后60秒启动,并且你每次都要求这个,这个时间已经过去了。

这就是混乱的地方,你应该只使用new Handler.postDelayed(Runnnable r, 60000)之类的呼叫而不是警报管理器。它将更准确,并且在理解Android操作系统及其警报/时钟/等等时不会遇到一些问题。

但是对于您的具体情况,我相信您可以通过访问System函数调用/变量来解决它。所以你的函数setNextScanAlarm()内部我认为它看起来像这样:

   public static void setNextScanAlarm(Context context, int interval) {
        //create the intent the same way as before
        Intent scanIntent = new Intent(context, AlarmReceiver.class);
        scanIntent.putExtra("interval", interval);
        scanIntent.putExtra("action", "scan");
        PendingIntent pendingIntent = PendingIntent.getBroadcast(
                context,
                0,
                scanIntent,
                PendingIntent.FLAG_ONE_SHOT);

        //create new variables to calculate the correct time for this to go off
        long timeRightNow = System.elapsedRealTime() //use something else if you change AlarmManager type
        long timeWhenIShouldGoOff = timeRightNow + interval;

        //use the new timeWhenIShouldGoOff variable instead of interval
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        alarmManager.set(
                AlarmManager.ELAPSED_REALTIME_WAKEUP,
                timeWhenIShouldGoOff,
                pendingIntent);
    }

答案 1 :(得分:0)

请参阅my answer一个类似的问题。 我在短时间间隔(不到1分钟)内使用postDelayed()代替AlarmManager,并且AlarmManager使用了很长时间。