Created
June 18, 2021 14:13
-
-
Save mahendranv/16c4354be67215f0e24c78da9882eef1 to your computer and use it in GitHub Desktop.
A timer that race to a given time and declutters activity.
This file contains hidden or 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
import android.os.CountDownTimer | |
import androidx.lifecycle.* | |
/** | |
* Any lifecycle owner that need a timer should implement this. | |
*/ | |
interface TimerCallback : LifecycleOwner { | |
fun onTick(millisUntilFinished: Long) | |
fun onTimeOut() | |
} | |
/** | |
* Countdown timer that is aware of lifecycle of activity/fragment. It avoids need to implement | |
* lifecycle methods on the caller end and enforce to implement `onTick` and `onTimeOut`. Also delivers | |
* the timeout when activity/fragment resumed if the time is past. | |
* | |
* Caller should make sure to keep reference to the timer and start & discard to make sure duplicate | |
* timers not running in parallel. Once the timer finish it will off-hook itself. | |
* | |
* | |
* Usage: | |
* ```kotlin | |
* val timer: LifecycleAwareTimer? = null | |
* | |
* fun startMyTimer() | |
* { | |
* val duration = 10*1000 // 10 sec timer | |
* timer?.discardTimer() // discard old timer to avoid | |
* timer = LifecycleAwareTimer(duration = duration, interval = 1000, this@SomeActivity/Fragment) | |
* timer?.startTimer() | |
* } | |
* ``` | |
*/ | |
class LifecycleAwareTimer( | |
private val duration: Long, | |
private val interval: Long, | |
private val callback: TimerCallback | |
) : LifecycleObserver { | |
private val stopAt: Long = System.currentTimeMillis() + duration | |
private var timer: CountDownTimer? = null | |
private val expired: Boolean | |
get() = (stopAt - System.currentTimeMillis()) <= 0 | |
init { | |
callback.lifecycle.addObserver(this) | |
} | |
/** | |
* Create and start a CountDownTimer if needed. Also discards the previous timer (since timer | |
* cannot be resumed and always start at the initial eta). | |
*/ | |
fun startTimer() { | |
timer?.cancel() | |
timer = null | |
val eta = stopAt - System.currentTimeMillis() | |
timer = object : CountDownTimer( | |
eta, interval) { | |
override fun onTick(millisUntilFinished: Long) { | |
callback.onTick(millisUntilFinished) | |
} | |
override fun onFinish() { | |
callback.onTimeOut() | |
callback.lifecycle.removeObserver(this@LifecycleAwareTimer) | |
} | |
} | |
timer?.start() | |
} | |
/** | |
* Cancels the timer and off-hook from lifecycle callbacks | |
*/ | |
fun discardTimer() { | |
timer?.cancel() | |
callback.lifecycle.removeObserver(this) | |
} | |
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME) | |
fun onResume() { | |
if (expired) { | |
callback.onTimeOut() | |
discardTimer() | |
} else { | |
startTimer() | |
} | |
} | |
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) | |
fun onPause() { | |
timer?.cancel() | |
} | |
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) | |
fun onDestroy() { | |
discardTimer() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment