Skip to content

Instantly share code, notes, and snippets.

@mfdeveloper
Forked from kasparsj/CountUpTimer.java
Last active January 30, 2023 15:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mfdeveloper/000c1f0fabbf9b362236e21add586b38 to your computer and use it in GitHub Desktop.
Save mfdeveloper/000c1f0fabbf9b362236e21add586b38 to your computer and use it in GitHub Desktop.
Java pooling: An infinite timer

CountDownTimerInfinite: An infinite timer

Based in CountUpTimer.java: An infinite timer, I did this fork to improve the implementation and use Kotlin language. You can use that for pooling requests on any action that needs run for an uncertain time.

Additionally, this implementation use Kotlin DSL as a flexible way to register listeners :)

That was tested in a Android app example using Android Studio Dolphin and latest api's for that moment (API 32 and 33) :)

Usage

Java

// Instantiate the class and pass the each tick time: (30000 = 30 seconds)
CountDownTimerInfinite poolingTimer = new CountDownTimerInfinite(30000);

// Run some action on "onTickListener" event. You can use segregation interface
// principle (from Java classes) or Kotlin DSL (from Kotlin classes)
poolingTimer.setOnTickListener((millis) -> {
  
   // Your action here: (e.g API REST request)
   myRepository.fetchSomething();
  
}).startTimer();

Kotlin

// Instantiate the class and pass the each tick time: (30000 = 30 seconds)
val poolingTimer = CountDownTimerInfinite(30000);

// Run some action on "onTickListener" event. You can use segregation interface
// principle (from Java classes) or Kotlin DSL (from Kotlin classes)
poolingTimer.setListeners {
    onTick { millis ->
  
       // Your action here: (e.g API REST request)
       myRepository.fetchSomething();
    }
}.startTimer();
package com.example.services.timers.listeners
/**
* Functional interface to allow use SOLID [Interface segregation principle](https://en.wikipedia.org/wiki/Interface_segregation_principle)
* from any Java class
*/
fun interface CancelListener {
/**
* "Event" triggered when [android.os.CountDownTimer.cancel] is called
*/
fun onCancel()
}
package com.example.services.timers
import android.os.CountDownTimer
import com.example.services.timers.listeners.CountDownTimerListenerWrapper
import com.example.services.timers.listeners.CancelListener
import com.example.services.timers.listeners.FinishListener
import com.example.services.timers.listeners.TickListener
/**
* An infinite **CountDownTimer** that runs each an interval of milliseconds
*
* This Class is based in:
* [CountUpTimer.java: An infinite timer](https://gist.github.com/kasparsj/10599789)
*/
open class CountDownTimerInfinite @JvmOverloads constructor(val countDownInterval: Long, protected var limitCycles: Int? = null) : CountDownTimer(Long.MAX_VALUE, countDownInterval) {
protected open var listener = CountDownTimerListenerWrapper()
var countDownCycle = 1
protected set
override fun onTick(millisUntilFinished: Long) {
limitCycles?.let {
if (countDownCycle >= it) {
stop()
return
}
}
listener.onTick(Long.MAX_VALUE * countDownCycle - millisUntilFinished)
countDownCycle++
}
override fun onFinish() {
listener.onFinish()
startTimer()
}
fun startTimer(): CountDownTimerInfinite {
return start() as CountDownTimerInfinite
}
fun cancelTimer(): CountDownTimerInfinite {
stop()
countDownCycle = 1
return this
}
fun stop(): CountDownTimerInfinite {
cancelTimer()
listener.onCancel()
return this
}
/**
* Set listeners defined in [CountDownTimerListenerWrapper]
* as Kotlin DSL, using [Function literals receiver](https://kotlinlang.org/docs/lambdas.html#function-literals-with-receiver).
*
* With this, you can register a listener for all callback methods once, or just one
* like described in SOLID [Interface segregation principle](https://en.wikipedia.org/wiki/Interface_segregation_principle) patterns
*
* ## Reference
*
* - [Listeners with several functions in Kotlin](https://antonioleiva.com/listeners-several-functions-kotlin)
*/
@Suppress("unused")
fun setListeners(init: CountDownTimerListenerWrapper.() -> Unit): CountDownTimerListenerWrapper {
listener.init()
return listener
}
//region Listeners Fluent Interfaces
@JvmName("setLimitCycles")
fun limitCycles(limitCycles: Int): CountDownTimerInfinite {
this.limitCycles = limitCycles
return this
}
@JvmName("setOnTickListener")
fun tickListener(tickListener: TickListener): CountDownTimerInfinite {
listener.onTick(tickListener)
return this
}
@JvmName("setOnCancelListener")
fun cancelListener(listener: CancelListener): CountDownTimerInfinite {
this.listener.onCancel(listener)
return this
}
@JvmName("setOnFinishListener")
fun finishListener(finishListener: FinishListener): CountDownTimerInfinite {
listener.onFinish(finishListener)
return this
}
//endregion
}
package com.example.services.timers.listeners
/**
* Listener wrapper for segregated interfaces that
* represents "events" of [com.example.services.timers.listeners.CountDownTimerInfinite]
*/
open class CountDownTimerListenerWrapper : TickListener, CancelListener, FinishListener {
var tickEvent: TickListener? = null
protected set
var cancelEvent: CancelListener? = null
protected set
var finishEvent: FinishListener? = null
protected set
//region Interfaces Overrides
override fun onTick(millisUntilFinished: Long) {
tickEvent?.onTick(millisUntilFinished)
}
override fun onCancel() {
cancelEvent?.onCancel()
}
override fun onFinish() {
finishEvent?.onFinish()
}
//endregion
//region Event Listeners
open fun onTick(callback: TickListener): CountDownTimerListenerWrapper {
tickEvent = callback
return this
}
open fun onCancel(listener: CancelListener): CountDownTimerListenerWrapper {
cancelEvent = listener
return this
}
open fun onFinish(listener: FinishListener): CountDownTimerListenerWrapper {
finishEvent = listener
return this
}
//endregion
}
import android.os.CountDownTimer;
/**
* Deprecated. Prefer use {@link CountDownTimerInfinite} class
* If you prefer use Java, you can just migrate the code to that language or
* use with interoperability between Kotlin x Java.
*
* The Kotlin class/interfaces here "@Jvm[Something]" annotations
* to improve the interoperability between the both languages :)
*/
@Deprecated
abstract public class CountUpTimer
{
private CountDownTimer countDownTimer;
private int countDownCycle;
public CountUpTimer(long countUpInterval) {
countDownTimer = new CountDownTimer(Long.MAX_VALUE, countUpInterval) {
@Override
public void onTick(long millisUntilFinished) {
CountUpTimer.this.onTick(Long.MAX_VALUE * countDownCycle - millisUntilFinished);
}
@Override
public void onFinish() {
countDownCycle++;
CountUpTimer.this.start();
}
};
countDownCycle = 1;
}
public void start() {
countDownTimer.start();
}
public void stop() {
countDownTimer.cancel();
}
public void cancel() {
stop();
countDownCycle = 1;
}
public abstract void onTick(long millisElapsed);
}
package com.example.services.timers.listeners
/**
* Functional interface to allow use SOLID [Interface segregation principle](https://en.wikipedia.org/wiki/Interface_segregation_principle)
* from any Java class
*/
fun interface FinishListener {
/**
* "Event" triggered when [android.os.CountDownTimer.onFinish] is called
*/
fun onFinish()
}
package com.example.services.timers.listeners
/**
* Functional interface to allow use SOLID [Interface segregation principle](https://en.wikipedia.org/wiki/Interface_segregation_principle)
* from any Java class
*/
fun interface TickListener {
/**
* "Event" triggered when [android.os.CountDownTimer.onTick] is called
*/
fun onTick(millisUntilFinished: Long)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment