Merge pull request #499 from fatihergin/fix/ISSUE-423-stopwatch-is-not-accurate

replace handler with timer for stopwatch tasks
This commit is contained in:
Tibor Kaputa 2023-08-21 23:23:34 +02:00 committed by GitHub
commit 1754a7233c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 50 additions and 31 deletions

View File

@ -199,13 +199,17 @@ class StopwatchFragment : Fragment() {
private val updateListener = object : Stopwatch.UpdateListener {
override fun onUpdate(totalTime: Long, lapTime: Long, useLongerMSFormat: Boolean) {
updateDisplayedText(totalTime, lapTime, useLongerMSFormat)
activity?.run {
updateDisplayedText(totalTime, lapTime, useLongerMSFormat)
}
}
override fun onStateChanged(state: Stopwatch.State) {
updateIcons(state)
binding.stopwatchLap.beVisibleIf(state == Stopwatch.State.RUNNING)
binding.stopwatchReset.beVisibleIf(state != Stopwatch.State.STOPPED)
activity?.run {
updateIcons(state)
binding.stopwatchLap.beVisibleIf(state == Stopwatch.State.RUNNING)
binding.stopwatchReset.beVisibleIf(state != Stopwatch.State.STOPPED)
}
}
}
}

View File

@ -1,16 +1,16 @@
package com.simplemobiletools.clock.helpers
import android.os.Handler
import android.os.Looper
import android.os.SystemClock
import com.simplemobiletools.clock.models.Lap
import java.util.Timer
import java.util.TimerTask
import java.util.concurrent.CopyOnWriteArraySet
private const val UPDATE_INTERVAL = 10L
object Stopwatch {
private val updateHandler = Handler(Looper.getMainLooper())
private var updateTimer = Timer()
private var uptimeAtStart = 0L
private var totalTicks = 0
private var currentTicks = 0 // ticks that reset at pause
@ -27,7 +27,7 @@ object Stopwatch {
private var updateListeners = CopyOnWriteArraySet<UpdateListener>()
fun reset() {
updateHandler.removeCallbacksAndMessages(null)
updateTimer.cancel()
state = State.STOPPED
currentTicks = 0
totalTicks = 0
@ -39,7 +39,7 @@ object Stopwatch {
fun toggle(setUptimeAtStart: Boolean) {
if (state != State.RUNNING) {
state = State.RUNNING
updateHandler.post(updateRunnable)
updateTimer = buildUpdateTimer()
if (setUptimeAtStart) {
uptimeAtStart = SystemClock.uptimeMillis()
}
@ -47,7 +47,7 @@ object Stopwatch {
state = State.PAUSED
val prevSessionsMS = (totalTicks - currentTicks) * UPDATE_INTERVAL
val totalDuration = SystemClock.uptimeMillis() - uptimeAtStart + prevSessionsMS
updateHandler.removeCallbacksAndMessages(null)
updateTimer.cancel()
currentTicks = 0
totalTicks--
for (listener in updateListeners) {
@ -97,23 +97,26 @@ object Stopwatch {
updateListeners.remove(updateListener)
}
private val updateRunnable = object : Runnable {
override fun run() {
if (state == State.RUNNING) {
if (totalTicks % 10 == 0) {
for (listener in updateListeners) {
listener.onUpdate(
totalTicks * UPDATE_INTERVAL,
lapTicks * UPDATE_INTERVAL,
false
)
private fun buildUpdateTimer(): Timer {
return Timer().apply {
scheduleAtFixedRate(object : TimerTask() {
override fun run() {
if (state == State.RUNNING) {
if (totalTicks % 10 == 0) {
for (listener in updateListeners) {
listener.onUpdate(
totalTicks * UPDATE_INTERVAL,
lapTicks * UPDATE_INTERVAL,
false
)
}
}
totalTicks++
currentTicks++
lapTicks++
}
}
totalTicks++
currentTicks++
lapTicks++
updateHandler.postAtTime(this, uptimeAtStart + currentTicks * UPDATE_INTERVAL)
}
}, 0, UPDATE_INTERVAL)
}
}

View File

@ -9,6 +9,7 @@ import android.os.Handler
import android.os.IBinder
import android.os.Looper
import androidx.core.app.NotificationCompat
import androidx.core.app.ServiceCompat
import androidx.core.content.ContextCompat
import com.simplemobiletools.clock.R
import com.simplemobiletools.clock.extensions.getFormattedDuration
@ -18,7 +19,6 @@ import com.simplemobiletools.clock.helpers.Stopwatch
import com.simplemobiletools.clock.helpers.Stopwatch.State
import com.simplemobiletools.clock.helpers.Stopwatch.UpdateListener
import com.simplemobiletools.commons.extensions.showErrorToast
import com.simplemobiletools.commons.helpers.isNougatPlus
import com.simplemobiletools.commons.helpers.isOreoPlus
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
@ -54,15 +54,15 @@ class StopwatchService : Service() {
}
override fun onDestroy() {
super.onDestroy()
bus.unregister(this)
Stopwatch.removeUpdateListener(updateListener)
super.onDestroy()
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onMessageEvent(event: StopwatchStopService) {
isStopping = true
stopForeground(true)
stopForegroundService()
}
private fun getServiceNotificationBuilder(
@ -98,17 +98,29 @@ class StopwatchService : Service() {
}
private val updateListener = object : UpdateListener {
private val MIN_NOTIFICATION_UPDATE_INTERVAL = 500L
private var lastUpdateTime = 0L
override fun onUpdate(totalTime: Long, lapTime: Long, useLongerMSFormat: Boolean) {
if (!isStopping) {
if (!isStopping && shouldNotificationBeUpdated()) {
lastUpdateTime = System.currentTimeMillis()
updateNotification(totalTime)
}
}
override fun onStateChanged(state: State) {
if (state == State.STOPPED && isNougatPlus()) {
stopForeground(STOP_FOREGROUND_REMOVE)
if (state == State.STOPPED) {
stopForegroundService()
}
}
private fun shouldNotificationBeUpdated(): Boolean {
return (System.currentTimeMillis() - lastUpdateTime) > MIN_NOTIFICATION_UPDATE_INTERVAL
}
}
private fun stopForegroundService() {
ServiceCompat.stopForeground(this@StopwatchService, ServiceCompat.STOP_FOREGROUND_REMOVE)
stopSelf()
}
}