CountUpTimer - compute elapsed time using real time
This commit is contained in:
parent
a06104534b
commit
bdfebac76d
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.lib.core.utils.timer
|
||||||
|
|
||||||
|
interface Clock {
|
||||||
|
fun epochMillis(): Long
|
||||||
|
}
|
||||||
|
|
||||||
|
class DefaultClock : Clock {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a UTC epoch in milliseconds
|
||||||
|
*
|
||||||
|
* This value is not guaranteed to be correct with reality
|
||||||
|
* as a User can override the system time and date to any values.
|
||||||
|
*/
|
||||||
|
override fun epochMillis(): Long {
|
||||||
|
return System.currentTimeMillis()
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,22 +28,23 @@ import java.util.concurrent.atomic.AtomicBoolean
|
||||||
import java.util.concurrent.atomic.AtomicLong
|
import java.util.concurrent.atomic.AtomicLong
|
||||||
|
|
||||||
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
|
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
|
||||||
class CountUpTimer(private val initialTime: Long = 0L, private val intervalInMs: Long = 1_000) {
|
class CountUpTimer(initialTime: Long = 0L, private val intervalInMs: Long = 1_000) {
|
||||||
|
|
||||||
private val coroutineScope = CoroutineScope(Dispatchers.Main)
|
private val coroutineScope = CoroutineScope(Dispatchers.Main)
|
||||||
private val elapsedTime: AtomicLong = AtomicLong(initialTime)
|
|
||||||
private val resumed: AtomicBoolean = AtomicBoolean(false)
|
private val resumed: AtomicBoolean = AtomicBoolean(false)
|
||||||
|
|
||||||
|
private val clock: Clock = DefaultClock()
|
||||||
|
private var lastTime: AtomicLong = AtomicLong()
|
||||||
|
private val elapsedTime: AtomicLong = AtomicLong(initialTime)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
startCounter()
|
startCounter()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startCounter() {
|
private fun startCounter() {
|
||||||
val internalDelay = if (intervalInMs > 100) intervalInMs / 10 else intervalInMs
|
tickerFlow(coroutineScope, intervalInMs)
|
||||||
tickerFlow(coroutineScope, internalDelay)
|
|
||||||
.filter { resumed.get() }
|
.filter { resumed.get() }
|
||||||
.map { elapsedTime.addAndGet(internalDelay) }
|
.map { addAndGetElapsedTime() }
|
||||||
.filter { (it - initialTime) % intervalInMs == 0L }
|
|
||||||
.onEach { tickListener?.onTick(it) }
|
.onEach { tickListener?.onTick(it) }
|
||||||
.launchIn(coroutineScope)
|
.launchIn(coroutineScope)
|
||||||
}
|
}
|
||||||
|
@ -55,19 +56,25 @@ class CountUpTimer(private val initialTime: Long = 0L, private val intervalInMs:
|
||||||
}
|
}
|
||||||
|
|
||||||
fun pause() {
|
fun pause() {
|
||||||
tickListener?.onTick(elapsedTime())
|
tickListener?.onTick(addAndGetElapsedTime())
|
||||||
resumed.set(false)
|
resumed.set(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resume() {
|
fun resume() {
|
||||||
|
lastTime.set(clock.epochMillis())
|
||||||
resumed.set(true)
|
resumed.set(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stop() {
|
fun stop() {
|
||||||
tickListener?.onTick(elapsedTime())
|
tickListener?.onTick(addAndGetElapsedTime())
|
||||||
coroutineScope.cancel()
|
coroutineScope.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun addAndGetElapsedTime(): Long {
|
||||||
|
val now = clock.epochMillis()
|
||||||
|
return elapsedTime.addAndGet(now - lastTime.getAndSet(now))
|
||||||
|
}
|
||||||
|
|
||||||
fun interface TickListener {
|
fun interface TickListener {
|
||||||
fun onTick(milliseconds: Long)
|
fun onTick(milliseconds: Long)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue