Skip to main content

Timers

danger

A timer's resolution is tied to the performance of the Scheduler loop. If there's a heavy computation involved, the timer may not fire at the exact time it was scheduled for.

For example, if you have a timer set to go off in 50ms, but the loop is busy for an extra 50ms, the timer will fire up to 100ms after it was scheduled.

This is not meant for very precise timing. But then again, without multithreading (which I don't reallly recommend for most cases), it's not really possible to get a higher resolution timer anyways. It's good enough for most use cases.

info

also doesn't work unless Scheduler is running.

Overview

Timers are simply an abstraction over the Listener API. They are a convenient way to schedule a function to be called after a certain amount of time, or to do a function until it reaches said time.

tip

For disposable timer use cases, look at the Timer.after() method for Java, or the after class for Kotlin.

These are very useful and cleaner than the raw Timer API in many cases!

Timer methods

Construction

Constructs a new Timer with the given delay. Timer is automatically started upon creation, but you can set it to pending by passing true as the second argument, or using startPending = true in Kotlin.

Params
  • length: long - The length of the timer. See the 'unit' parameter to set the time unit
  • startPending: boolean - Whether the timer should start in a pending state. If true, the timer will not start until you call `start()`
    - Defaults to: false
  • unit: TimeUnit - The time unit of the timer. Defaults to milliseconds
    - Defaults to: TimeUnit.MILLISECONDS
    Timer timer1 = new Timer(1000); // Ends after ~1000ms

    Timer timer2 = new Timer(1000, true); // Stays pending until you call start()

    Timer timer3 = new Timer(1, false, TimeUnit.SECONDS); // Ends after ~1 second

    timer.whileWaiting()

    Calls the given callback every Scheduler cycle while the timer is either running or pending.

    Params
  • callback: Runnable - The function to perform while waiting
  • Returns
  • Timer - The Timer itself to allow for method chaining
    Timer timer = new Timer(1000, true); // Timer is created in a pending state

    timer.whileWaiting(() -> {
    System.out.println("Hi!");
    });

    // "Hi!" is being printed every loop

    timer.start();

    // "Hi!" is still being printed every loop

    // 1000ms later...

    // "Hi!" is no longer being printed since the timer has ended

    timer.whileRunning()

    Calls the given callback every Scheduler cycle while the timer is started and running, and not pending.

    Params
  • callback: Runnable - The function to perform while running
  • Returns
  • Timer - The Timer itself to allow for method chaining
    Timer timer = new Timer(1000, true); // Timer is created in a pending state

    timer.whileRunning(() -> {
    System.out.println("Hi!");
    });

    // "Hi!" is not being printed since the timer is pending

    timer.start();

    // "Hi!" is being printed every loop now

    // 1000ms later...

    // "Hi!" is no longer being printed since the timer has ended

    timer.onDone()

    Calls the given callback when the timer ends.

    Params
  • callback: Runnable - The function to perform when the timer ends
  • Returns
  • Timer - The Timer itself to allow for method chaining
    Timer timer = new Timer(1000); // Timer is created started

    timer.onDone(() -> {
    System.out.println("Hi!");
    });

    // "Hi!" is not being printed since the timer is still running

    // 1000ms later...

    // "Hi!" is printed *once* when the timer ends

    timer.start()

    Resets the start time and takes the timer out of a pending state, effectively (re)starting the timer.

    Timer timer = new Timer(1000, true); // Timer is created in a pending state

    timer.start();

    // Timer is now running

    timer.setPending()

    Sets the timer to a pending state if nothing or true is passed, or takes it out of pending if false is passed.

    Params
  • pending: boolean - Whether the timer should be pending or not
    - Defaults to: true
    Timer timer = new Timer(1000); // Timer is created started

    timer.setPending();

    // Timer is now pending

    timer.setPending(false);

    // Timer is no longer pending

    timer.finishPrematurely()

    Stops the timer, still fires the onDone callback. Does not set the timer to a pending state.

    Timer timer = new Timer(1000); // Timer is created started

    timer.onDone(() -> {
    System.out.println("Hi!");
    });

    timer.stop(); // "Hi!" is still printed once

    // Timer is now stopped

    timer.isDone()

    Returns
  • boolean - Whether or not the timer has ended
  • literally what else do you need to know about this method

    timer.destroy()

    Clears the internal state of the timer, pending it and removing all callbacks. The timer is still usable after this, but everything needs to be resubscribed and the timer needs to be restarted.

    Not entirely sure why you'd want to do this, but it's there if you need it lol.

    after

    The Timer.after() method is a static method that creates a new timer and starts it immediately. After completion, the timer is automatically destroyed.

    It's great for one-off timers that don't need to be reused, especially for adding delay in callbacks!

    Construction

    Params
  • time: long - The duration of the timer in **ANY** unit (see below about Unit specification)
  • Unit specification

    The unit of the time parameter is specified by the method you call on the after instance.

    For example, if you want to create a timer that lasts for 5 seconds, you would do:

    Timer.after(5).seconds(() -> {
    // Do whatever
    });

    Here's a practical example:

    button.onFall(() -> {
    claw.openForDepositing();

    after(400).milliseconds(() -> { // You can do a static import for a more DSL-like syntax
    claw.close();
    });

    after(1).seconds(() -> {
    lift.goToZero();
    });

    after(2).unit(TimeUnit.MONTHS, () -> {
    System.out.print("I'm still here!");
    });
    }

    Practical usage example

    We use Timer.after() in all of our Task Chains, feel free to take a look through them:

    (They're in Kotlin, but they look similar to the Java version and the concepts carry forwards)

    Link to all of the Chains