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



我在AlarmManager.setExact((上挣扎了几天。我的应用程序需要精确的警报,并且在使用AlarmManager.setRepeating((的旧Android上运行良好。

我已经读到自 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设备上进行测试时,一切正常。闹钟始终在指定时间开始(屏幕打开/关闭(。不幸的是,当我断开设备与计算机的连接时,只有在屏幕打开时,警报才会正确启动。当我关闭屏幕时,警报开始的时间不准确。

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

它在Android <19上正常运行

没有。

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

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

startActivity()异步的。当onReceive()结束和框架管理的WakeLock(以及您的附加(发布时,活动将不会接近启动。现在,有时,您的活动无论如何都有机会启动,因为设备不会很快重新入睡。我假设您在活动中使用了android:keepScreenOn或等效物,因此一旦您到达该点,就会有另一个未完成WakeLock,并且设备无法自动重新入睡。

但是,有时设备确实会在您的活动开始之前重新入睡。这可能会在Android 5.0中发生变化 - 如果Android更积极地让设备更快地恢复睡眠状态,我一点也不会感到惊讶。因此,虽然您之前的方法可能在 90% 的时间内有效,但现在可能要少得多。但是,您之前的方法在 100% 的时间内都不起作用

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

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

最新更新