如何使一个有保证的实时秒表安卓系统



我正试图使用前台服务在我的应用程序中实现一个计时功能,本质上是一个秒表。以下是我正在做的事情的大致想法,当应用程序在前台时效果很好,但当屏幕关闭时效果不佳。

这是因为handler.postDelayed()不能保证是实时的,而且当屏幕关闭时,它离它很远

class TimerService: Service(), CoroutineScope {
private var currentTime: Int = 0
private val handler = Handler(Looper.getMainLooper())
private var runnable: Runnable = object : Runnable {
override fun run() {
if (timerState == TimerState.START) {
currentTime++
}
broadcastUpdate()
// Repeat every 1 second
handler.postDelayed(this, 1000)
}
}
private val job = Job()
override val coroutineContext: CoroutineContext
get() = Dispatchers.IO + job
// Call this to start the timer
private fun startCoroutineTimer() {
launch(coroutineContext) {
handler.post(runnable)
}
}
// Rest of the service class
...
}

我的问题是,做这种事情的精明方法是什么?我需要能够保证,使用前台服务,我可以制作一个准确的秒表,能够启动、暂停、恢复和停止。

我已经处理好了国家广播和其他一切,但实际的计时器部分是我被卡住的地方,我似乎找不到一个简单有效的、保证准确的解决方案。

首先从不同的操作系统开始。有一整类操作系统称为RTOS(实时操作系统(。Linux(以及安卓系统(不是其中之一。如果您确实需要实时性,linux是不可接受的解决方案。

但假设你实际上并不需要实时性,你只需要更高的准确性。有几种方法可以轻松地改进代码。

最重要的是,您当前的代码假设计时器每秒会熄灭一次。不要那样做。相反,记下计时器启动的时间。每次计时器熄灭时,获取当前时间。经过的时间是增量。这样,任何累积的不准确都会在每次勾选时被抹去。这也将修复许多屏幕关闭的情况,因为屏幕打开后的第一次更新将更新到正确的时间。

private var timeStarted : Long = 0
private var timeElapsed : Long = 0
private var runnable: Runnable = object : Runnable {
override fun run() {
if (timerState == TimerState.START) {
timeElapsed = System.getCurrentTimeMillis() - timeStarted
}
broadcastUpdate()
// Repeat every 1 second
handler.postDelayed(this, 1000)
}
}
private fun startCoroutineTimer() {
timeStarted = System.getCurrentTimeMillis()
handler.post(runnable)
}

还要注意,您不需要协同程序来发布到处理程序。处理程序负责多线程处理,在那里启动协程不会提供任何值。

最新更新