设备处于休眠状态时可运行的Android计时器

时间:2011-02-07 05:00:18

标签: android timer clock persistent reliability

我正在编写一个体育应用,需要跟踪季度/半/周期的经过时间。经过的时间需要精确到秒。即使用户通过按电源按钮明确将设备置于睡眠模式,游戏时钟也需要继续运行。

我的第一次尝试涉及使用 Handler.postDelayed()来触发每200ms的时钟滴答和 WindowManager.LayoutParms.FLAG_KEEP_SCREEN_ON 以确保“时钟”不是屏幕超时停止了。但我很快就了解到,按下电源按钮手动将设备置于睡眠状态可以绕过这种方法。此外,postDelayed()方法正在经历一些时钟漂移,显然是在run()方法中花费的时间的结果。实际的数字仍然是准确的,但不是对齐,例如,在用户容易理解的5秒边界上 - 所涉及的定时器开始漂移,导致一些可理解的用户混淆。

经过一番研究后,我找到了使用服务的技术,java timersAlarmManagerPartialWakeLock来实现计时器。服务本身不能解决与设备进入睡眠状态相关的问题。 Java定时器(如服务)无法解决设备进入休眠状态的问题。 AlarmManager似乎是一个很好的方法,但我担心这不适合使用AlarmManager(即报警之间的间隔非常短)。使用PartialWakeLock看起来也很有希望,但它本身并没有解决我遇到的时钟漂移问题。

我将尝试组合AlarmManager和PartialWakeLock。我们的想法是,AlarmManager将有助于对抗时钟漂移和PartialWakeLock,以帮助保持代码简单(手指交叉)。我希望这种方法能够在节能,代码复杂性和用户期望之间取得合理的平衡。非常感谢任何建议。

谢谢,

2 个答案:

答案 0 :(得分:4)

我对上面的原帖有部分解决方案。它尚未解决与 postDelayed()处理期间计算所花费的时间相关的时钟漂移,但它是向前迈出的一步。此外,它看似简单,总是一个好兆头。

当我应该使用 SystemClock.elapsedRealtime()时,我发现我正在使用 SystemClock.uptimeMillis()。 2之间的区别是微妙的,但很重要。

正如您所料,我的解决方案通过累积对postDelayed() - ,经过时间= elapsedTime + lastClockInterval 的调用之间的持续时间来跟踪经过的时间。如上所述,原始实现使用 uptimeMillis()。仔细阅读javadoc reveals that uptimeMillis()不包括在“深度睡眠”中花费的时间,例如,当用户按下电源按钮时。但 elapsedRealtime()方法确实包括在“深度睡眠”模式下花费的时间。跟踪深度睡眠周期时间所需的全部内容是用 elapsedRealtime()替换 uptimeMillis()的使用。成功!无需使用AlarmManager,PartialWakeLock或任何其他更复杂的东西。当然,这些方法仍然有用,但在实现简单的经过时间的时钟或计时器时它们是过度的。

要解决的下一个问题是由与 postDelayed()处理相关的非零执行时间引起的时钟漂移。我希望产生一个线程来进行处理将解决这个问题,允许 postDelayed()或多或少地模仿异步调用。另一种方法是调整 postDelayed()延迟时间,以考虑在 postDelayed()中花费的时间。我会发布我的结果。

在一个不相关的说明中,在我的调查过程中,我将自己对待CommonsWare Warescription。虽然我没有直接使用此来源的任何想法来解决这个问题,但我认为在可预见的未来它将成为我的Android首选信息源。我通过我的日常工作获得了O'Reilly订阅,但我发现CommonsWare书籍至少与Android开发的信息来源一样好,如果不是更好,那就是O'Reilly资源。我发现O'Reilly Safari资源非常好。有趣...

干杯, 富

答案 1 :(得分:0)

对不起,这不是一个相当的答案,但我觉得你的过程是类似地雷,但在关于代码有一点要清楚你是怎么周围的睡眠问题。我没有漂移,但是应用进入睡眠模式后确实会挂起,然后在显示器处于活动状态时会向前重置,然后在设备进入睡眠状态时再次挂起。这是定时器过程的核心。

    Handler timerHandler = new Handler();
Runnable timerRunnable = new Runnable() {

    @Override
    public void run() {

        // do something here to display

        processTime();    // process what to be done on a sec by sec basis
        try {
            timerHandler.postDelayed(this, 1000
        } catch (Exception ex){

        }

    }
};

在这里是否可以做一些事情以使其在睡眠模式下继续运行?用于在较旧版本的android /设备上使用。