Skip to content

Instantly share code, notes, and snippets.

@abdullahi-usman
Created February 16, 2020 17:28
Show Gist options
  • Save abdullahi-usman/885d6d648a498f0244ccfcabd4bd6301 to your computer and use it in GitHub Desktop.
Save abdullahi-usman/885d6d648a498f0244ccfcabd4bd6301 to your computer and use it in GitHub Desktop.
Modified version of Android's CountDownTimer with option to run indefinately.
package com.dahham.ora
import android.os.Handler
import android.os.Message
import android.os.SystemClock
abstract class CountDownTimer
/**
* @param millisInFuture The number of millis in the future from the call
* to [.start] until the countdown is done and [.onFinish]
* is called or 0 to run indefinitely.
* @param countDownInterval The interval along the way to receive
* [.onTick] callbacks.
*/(
/**
* Millis since epoch when alarm should stop.
*/
private val mMillisInFuture: Long,
/**
* The interval in millis that the user receives callbacks
*/
private val mCountdownInterval: Long
) {
private var mStopTimeInFuture: Long = 0
/**
* boolean representing if the timer was cancelled
*/
private var mCancelled = false
/**
* Cancel the countdown.
*/
@Synchronized
fun cancel() {
mCancelled = true
mHandler.removeMessages(MSG)
}
/**
* Start the countdown.
*/
@Synchronized
fun start(): CountDownTimer {
mCancelled = false
if (mMillisInFuture < 0) {
onFinish()
return this
}
mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture
mHandler.sendMessage(mHandler.obtainMessage(MSG))
return this
}
/**
* Callback fired on regular interval.
* @param millisUntilFinished The amount of time until finished.
*/
abstract fun onTick(millisUntilFinished: Long)
/**
* Callback fired when the time is up.
*/
abstract fun onFinish()
// handles counting down
private val mHandler: Handler = object : Handler() {
override fun handleMessage(msg: Message) {
synchronized(this@CountDownTimer) {
if (mCancelled) {
return
}
val millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime()
if (mMillisInFuture != 0L && millisLeft <= 0) {
onFinish()
} else {
val lastTickStart = SystemClock.elapsedRealtime()
onTick(millisLeft)
// take into account user's onTick taking time to execute
val lastTickDuration =
SystemClock.elapsedRealtime() - lastTickStart
var delay: Long
if (mMillisInFuture == 0L){
delay = mCountdownInterval
}else if (millisLeft < mCountdownInterval) { // just delay until done
delay = millisLeft - lastTickDuration
// special case: user's onTick took more than interval to
// complete, trigger onFinish without delay
if (delay < 0) delay = 0
} else {
delay = mCountdownInterval - lastTickDuration
// special case: user's onTick took more than interval to
// complete, skip to next interval
while (delay < 0) delay += mCountdownInterval
}
sendMessageDelayed(obtainMessage(MSG), delay)
}
}
}
}
companion object {
private const val MSG = 1
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment