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
|
||||
|
||||
@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 elapsedTime: AtomicLong = AtomicLong(initialTime)
|
||||
private val resumed: AtomicBoolean = AtomicBoolean(false)
|
||||
|
||||
private val clock: Clock = DefaultClock()
|
||||
private var lastTime: AtomicLong = AtomicLong()
|
||||
private val elapsedTime: AtomicLong = AtomicLong(initialTime)
|
||||
|
||||
init {
|
||||
startCounter()
|
||||
}
|
||||
|
||||
private fun startCounter() {
|
||||
val internalDelay = if (intervalInMs > 100) intervalInMs / 10 else intervalInMs
|
||||
tickerFlow(coroutineScope, internalDelay)
|
||||
tickerFlow(coroutineScope, intervalInMs)
|
||||
.filter { resumed.get() }
|
||||
.map { elapsedTime.addAndGet(internalDelay) }
|
||||
.filter { (it - initialTime) % intervalInMs == 0L }
|
||||
.map { addAndGetElapsedTime() }
|
||||
.onEach { tickListener?.onTick(it) }
|
||||
.launchIn(coroutineScope)
|
||||
}
|
||||
|
@ -55,19 +56,25 @@ class CountUpTimer(private val initialTime: Long = 0L, private val intervalInMs:
|
|||
}
|
||||
|
||||
fun pause() {
|
||||
tickListener?.onTick(elapsedTime())
|
||||
tickListener?.onTick(addAndGetElapsedTime())
|
||||
resumed.set(false)
|
||||
}
|
||||
|
||||
fun resume() {
|
||||
lastTime.set(clock.epochMillis())
|
||||
resumed.set(true)
|
||||
}
|
||||
|
||||
fun stop() {
|
||||
tickListener?.onTick(elapsedTime())
|
||||
tickListener?.onTick(addAndGetElapsedTime())
|
||||
coroutineScope.cancel()
|
||||
}
|
||||
|
||||
private fun addAndGetElapsedTime(): Long {
|
||||
val now = clock.epochMillis()
|
||||
return elapsedTime.addAndGet(now - lastTime.getAndSet(now))
|
||||
}
|
||||
|
||||
fun interface TickListener {
|
||||
fun onTick(milliseconds: Long)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue