Created
February 16, 2020 17:28
-
-
Save abdullahi-usman/885d6d648a498f0244ccfcabd4bd6301 to your computer and use it in GitHub Desktop.
Modified version of Android's CountDownTimer with option to run indefinately.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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