Android 定时器在设备睡眠时工作
我正在编写一个体育应用程序,需要跟踪季度/半场/周期的经过时间。经过的时间需要精确到秒。即使用户通过按下电源按钮明确将设备置于睡眠模式,游戏时钟也需要继续运行。
我的第一次尝试涉及使用 Handler.postDelayed() 每 200 毫秒触发一次时钟滴答声,并使用 WindowManager.LayoutParms.FLAG_KEEP_SCREEN_ON 确保“时钟”不会停止通过屏幕超时。但我很快了解到,可以通过按电源按钮手动使设备进入睡眠状态来绕过这种方法。此外,postDelayed() 方法正在经历一些时钟漂移,这显然是由于 run() 方法所花费的时间造成的。实际数字仍然准确,但不是在用户容易理解的 5 秒边界上对齐 - 所涉及的计时器开始漂移,导致一些可以理解的用户困惑。
经过一番研究后,我发现了使用服务的技术,java 计时器,AlarmManager 和 PartialWakeLock 来实现计时器。服务本身无法解决与设备进入睡眠状态相关的问题。 Java 计时器与服务一样,不能解决设备进入睡眠状态的问题。 AlarmManager 似乎是一个很好的方法,但我担心这不是 AlarmManager 的适当使用(即警报之间的间隔非常短)。使用 PartialWakeLock 看起来也很有希望,但它本身并不能解决我遇到的时钟漂移问题。
我将尝试 AlarmManager 和 PartialWakeLock 的组合。这个想法是 AlarmManager 将帮助对抗时钟漂移和 PartialWakeLock 来帮助保持代码简单(交叉手指)。我希望这种方法能够在节能、代码复杂性和用户期望之间取得合理的平衡。非常感谢任何建议。
谢谢,
里奇
I'm writing a sports app that needs to track the elapsed time of quarter/half/period. Elapsed time needs to be accurate to the second. The game clock needs to continue to run even if the user explicitly places the device in sleep mode by pressing the power button.
My first attempt at this involved using Handler.postDelayed() to trigger the clock ticks every 200ms and WindowManager.LayoutParms.FLAG_KEEP_SCREEN_ON to ensure that the "clock" wasn't stopped by a screen timeout. But I soon learned that it was possible to circumvent this approach by pressing the power button to manually put the device to sleep. In addition, the postDelayed() approach is experiencing some clock drift, apparently a result of the time spent in the run() method. The actual numbers are still accurate, but instead of being aligned, for example, on 5 second boundaries which are easily understood by users - the timers involved start to drift, resulting in some understandable user confusion.
After a bit of research I found techiques for using services, java timers, AlarmManager, and PartialWakeLock to implement timers. Services by themselves won't solve the problem associated with the device going to sleep. Java timers, like services, don't solve the problem with the device going to sleep. AlarmManager seems like a good approach, but I'm concerned that this isn't an appropriate use of AlarmManager (i.e., very short intervals between alarms). Using PartialWakeLock also looks promising, but by itself it doesn't address the clock-drift problem I'm experiencing.
I'm going to try a combination of AlarmManager and PartialWakeLock. The idea is that AlarmManager will help combat clock-drift and PartialWakeLock to help keep the code simple (fingers-crossed). I'm hoping that this approach will result in a reasonable balance between power conservation, code complexity, and user expectations. Any advice is greatly appreciated.
Thanks,
Rich
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我对上面的原始帖子有部分解决方案。它尚未解决与 postDelayed() 处理期间的计算时间相关的时钟漂移问题,但它是向前迈出的一步。此外,它看似简单,总是一个好兆头。
事实证明,当我应该使用 SystemClock.elapsedRealtime() 时,我却使用了 SystemClock.uptimeMillis()。两者之间的区别很微妙,但很重要。
正如您所期望的,我的解决方案通过累积调用 postDelayed() 之间的持续时间来跟踪经过的时间 - 即,经过的时间 = elapsedTime + lastClockInterval。如上所述,原始实现使用了uptimeMillis()。仔细阅读 javadoc 可以发现 uptimeMillis() 不包括“深度睡眠”所花费的时间,例如,当用户按下电源按钮时。但elapsedRealtime()方法确实包括在“深度睡眠”模式下花费的时间。跟踪深度睡眠周期的时间所需要做的就是将 uptimeMillis() 的使用替换为 elapsedRealtime()。成功!无需使用 AlarmManager、PartialWakeLock 或任何其他更复杂的东西。诚然,这些方法仍然有用途,但在实现简单的经过时间的时钟或计时器时它们就太过分了。
下一个要解决的问题是与 postDelayed() 处理相关的非零执行时间引起的时钟漂移。我希望生成一个线程来进行处理能够解决这个问题,从而允许 postDelayed() 或多或少地模仿异步调用。另一种方法是调整 postDelayed() 延迟时间,以考虑 postDelayed() 所花费的时间。我会发布我的结果。
顺便说一句,在我的调查过程中,我给自己看了一份 CommonsWare Warescription。虽然我没有直接使用此来源的任何想法来解决这个问题,但我确实认为在可预见的将来它将成为我的 Android 首选信息源。我通过日常工作订阅了 O'Reilly,但我发现 CommonsWare 书籍作为有关 Android 开发的信息来源,即使不是更好,也至少与 O'Reilly 资源一样好。我发现 O'Reilly Safari 资源非常好。有趣...
干杯,
富有的
I've got a partial solution to my original post above. It doesn't yet address the clock drift associated with the time spent in calculations during the postDelayed() processing, but it is a step forward. In addition, it's deceptively simple, always a good sign.
It turns out I was using SystemClock.uptimeMillis() when I should have been using SystemClock.elapsedRealtime(). The difference between the 2 is subtle, but important.
As you might expect, my solution keeps track of elapsed time by accumulating durations between calls to postDelayed() - i.e., elapsed time = elapsedTime + lastClockInterval. As stated above, the original implementation used uptimeMillis(). Careful reading of the javadoc reveals that uptimeMillis() doesn't include time spent in "deep sleep", e.g., when the user presses the power button. But the elapsedRealtime() method does include time spent in "deep sleep" mode. All that was required to track time across deep sleep cycles was to replace the use of uptimeMillis() with elapsedRealtime(). Success! No need to use AlarmManager, PartialWakeLock, or anything else substantially more complicated. Granted, these methods still have uses, but they are overkill when implementing a simple elapsed-time clock or timer.
The next problem to tackle is with the clock-drift caused by the non-zero execution time associated with postDelayed() processing. I'm hoping that spawning a thread to do the processing will address this issue, allowing postDelayed() to more or less mimic an asynchronous call. Another approach would be to adjust the postDelayed() delay time to take into account the time spent in postDelayed(). I'll post my results.
On an unrelated note, during my investigation I treated myself to a CommonsWare Warescription. While I didn't directly use any ideas from this source for this problem, I do think that it is going to be my Android go-to information source for the foreseeable future. I've got an O'Reilly subscription through my day job, but I've found the CommonsWare books to be as least as good, if not better, source of information about Android development as the O'Reilly resources. And I have found the O'Reilly Safari resources to be pretty good. Interesting...
Cheers,
Rich
很抱歉,这不是一个完整的答案,但我觉得您的过程与我的类似,但几乎没有代码可以清楚地说明您如何解决睡眠问题。我没有漂移,但应用程序在进入睡眠模式时确实会挂起,然后在显示器处于活动状态时向前重置,然后在设备睡眠时再次挂起。这是定时器流程的核心。
我可以做些什么来让它在睡眠模式下继续吗?此功能适用于旧版本的 Android/设备。
I'm sorry this is not quite an answer, but I feel your process is similar to mine, but there was little in regards to code to make it clear how you got around the sleep issue. I don't have drift, but the app does hang when it goes into sleep mode,then kind of resets forward when the display is active, then hangs again when the device sleeps. This is the core of the timer process.
Is there something here that I can do to allow it to continue when in sleep mode? This use to work on older version of android/devices.