mirror of
				https://github.com/SimpleMobileTools/Simple-Clock.git
				synced 2025-06-05 22:19:17 +02:00 
			
		
		
		
	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:
		| @@ -199,13 +199,17 @@ class StopwatchFragment : Fragment() { | ||||
|  | ||||
|     private val updateListener = object : Stopwatch.UpdateListener { | ||||
|         override fun onUpdate(totalTime: Long, lapTime: Long, useLongerMSFormat: Boolean) { | ||||
|             activity?.run { | ||||
|                 updateDisplayedText(totalTime, lapTime, useLongerMSFormat) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         override fun onStateChanged(state: Stopwatch.State) { | ||||
|             activity?.run { | ||||
|                 updateIcons(state) | ||||
|                 binding.stopwatchLap.beVisibleIf(state == Stopwatch.State.RUNNING) | ||||
|                 binding.stopwatchReset.beVisibleIf(state != Stopwatch.State.STOPPED) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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,7 +97,9 @@ object Stopwatch { | ||||
|         updateListeners.remove(updateListener) | ||||
|     } | ||||
|  | ||||
|     private val updateRunnable = object : Runnable { | ||||
|     private fun buildUpdateTimer(): Timer { | ||||
|         return Timer().apply { | ||||
|             scheduleAtFixedRate(object : TimerTask() { | ||||
|                 override fun run() { | ||||
|                     if (state == State.RUNNING) { | ||||
|                         if (totalTicks % 10 == 0) { | ||||
| @@ -112,9 +114,10 @@ object Stopwatch { | ||||
|                         totalTicks++ | ||||
|                         currentTicks++ | ||||
|                         lapTicks++ | ||||
|                 updateHandler.postAtTime(this, uptimeAtStart + currentTicks * UPDATE_INTERVAL) | ||||
|                     } | ||||
|                 } | ||||
|             }, 0, UPDATE_INTERVAL) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     enum class State { | ||||
|   | ||||
| @@ -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() | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user