13

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

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

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

我将尝试结合使用 AlarmManager 和 PartialWakeLock。这个想法是 AlarmManager 将帮助对抗时钟漂移和 PartialWakeLock 以帮助保持代码简单(手指交叉)。我希望这种方法能够在节能、代码复杂性和用户期望之间取得合理的平衡。任何意见是极大的赞赏。

谢谢,

富有的

4

2 回答 2

4

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

事实证明,当我应该使用SystemClock.elapsedRealtime()时,我正在使用SystemClock.uptimeMillis()。两者之间的区别是微妙的,但很重要。

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

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

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

干杯,有钱

于 2011-02-09T04:47:04.847 回答
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/devices 上工作。

于 2019-01-31T20:17:36.490 回答