当手机睡眠时,AlarmManager.setExact在Kitkat中仍然不准确

时间:2014-12-21 12:05:39

标签: android alarmmanager android-4.4-kitkat

我正在努力使用AlarmManager.setExact()几天。我的应用程序需要精确的警报,并且可以使用AlarmManager.setRepeating()在旧的Androids上正常工作。

我已经读过自API 19以来它已经改变并相应地更新了我的代码。

以下是负责设置闹钟的代码:

PendingIntent pi = PendingIntent.getBroadcast(context.getApplicationContext(), alarmOrder+1, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        getAlarmManager(context).setExact(AlarmManager.RTC_WAKEUP, alarmTimeMillis, pi);
    }
    else {
        getAlarmManager(context).setRepeating(AlarmManager.RTC_WAKEUP, alarmTimeMillis, AlarmManager.INTERVAL_DAY, pi);
    }

广播接收器通过闹钟屏幕启动新活动:

@Override
public void onReceive(Context context, Intent intent) {
    PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AlarmTimeReceiver");
    wl.acquire();

    Intent alarmIntent = new Intent(context, AlarmActivity.class);
    alarmIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
    context.startActivity(alarmIntent);

    //Release the lock
    wl.release();
}

事情是,在通过USB线连接的Android 4.4设备上进行测试时,一切正常。报警始终在指定的时间开始(屏幕打开/关闭)。不幸的是,当我从计算机断开设备时,只有在打开屏幕时才能正确启动警报。当我关闭屏幕时,警报会在不准确的时间内启动。

我错过了什么吗?你们有没有经历过类似的情况?

1 个答案:

答案 0 :(得分:5)

  

它在Android上正确运行< 19

不是。

_WAKEUP警报通过框架管理WakeLock保证 - 设备将保持清醒状态,直到onReceive()返回。然后,框架会释放WakeLock,如果没有其他未完成的WakeLocks,设备可能会重新入睡。

你写的WakeLock毫无意义。它只是复制了框架管理的WakeLock而没有增加价值。

startActivity() 异步。活动不会在时间onReceive()结束时接近开始,并且框架管理的WakeLock(以及您的附加版本)将被释放。现在,有时,您的活动无论如何都将有机会启动,因为设备不会快速回到睡眠状态。我假设你在活动中使用android:keepScreenOn或等效物,所以一旦你到达那一点,还有另外一个WakeLock未完成,并且设备无法自动回退。

但是,有时设备会在您的活动开始之前回来睡着。 那个可能已经在Android 5.0中发生了变化 - 如果Android更加积极地让设备重新入睡,那么我不会感到惊讶。因此,虽然您之前的方法可能在90%的时间内都有效,但现在可能要少得多。但是,您之前的方法在100%的时间内无法正常工作

我们看到服务也是如此。事实上,这种情况在那里更为常见。这就是为什么,在2009年4月,我创建了the WakefulIntentService,以及为什么在2013年8月,Google released WakefulBroadcastReceiver。两者都提供了一种模式,用于获取WakeLock中的onReceive(),但在服务工作完成之前不会发布它。

这些解决方案都不适合您,因为两者都与服务密不可分。但是,您可以将它们作为创建自己的想法来源。您需要将WakeLock移动到静态数据成员(ick)中,并且只有release()一旦您的活动足够远,它就拥有自己的WakeLock。例如,如果您在Java代码中setKeepScreenOn()上调用View,那么一旦完成,我认为发布原始WakeLock是安全的。然后,框架可以根据用户输入接管并释放保持屏幕WakeLock