1

I want to implement a timer in JavaFX and have come across this piece of code but I don't know where to put it inside my project files. Also is this the correct way to implement a timer? I want the timer to run whenever the scene is changed. So do I put it inside the initialize method of the Initializable interface or somewhere else?

final int[] secondsPassed = {0};
    Timer myTimer = new Timer();
    TimerTask task = new TimerTask() {
        @Override
        public void run() {
            secondsPassed[0]++;
            Platform.runLater(() -> timerLabel.setText(String.valueOf(secondsPassed[0])));
            ;
        }
    };

    myTimer.scheduleAtFixedRate(task,1000,1000);

Also why is the variable secondsPassed a final int array?

  • 3
    My answer [here](https://stackoverflow.com/a/61333413/6395627) has an example countdown-timer implementation. My other answer [here](https://stackoverflow.com/a/61333767/6395627) has an example stopwatch implementation. Both are very similar to each other and make use of `AnimationTimer`, meaning everything happens on the FX thread. – Slaw May 28 '20 at 07:38

1 Answers1

0

It makes sense to execute this peace of code when the Scene is created. I will put it in the initilize() method inside the controller that has the timerLabel.

In your code you are creating a Timer, with a TimerTask that will be executed once per second (1000ms). This Timer is executed in a different Thread so you need to use Platform.runLater to come back to the UI thread and perform the change in the interface (if not it will throw an error because you cannot modify interface elements outside the UI thread).

Finally, the variable secondsPassed has been declared as final because it is required to be used inside the TimerTask which has been declared as an anonymous inner class (check here for more information). As the array is final you cannot modify it. What you can do is modify its elements. In this case we only have one element (position 0), that you are using for counting the seconds.

pglez82
  • 489
  • 5
  • 11
  • 2
    Perhaps an [`AtomicInteger`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/atomic/AtomicInteger.html) would be more appropriate than an array of `int` for use as that `final` variable? – Basil Bourque May 28 '20 at 06:11
  • Thanks a lot! But is this the correct way to implement a timer? If not are there others? –  May 28 '20 at 06:12
  • 1
    @Ak222 No: this is not the correct way to implement a timer in JavaFX. There are many flaws in this code, e.g. modifying state shared across multiple without synchronization (there is no guarantee the FX Application will ever see changes made to `secondsPassed` on the background thread), using background threads when they are not necessary (the `Animation` API gives better alternatives), and since there's no guarantee the `TimerTask` is executed once *exactly* every second, the timer will be inaccurate. See the comment under the question for better implementations. – James_D May 28 '20 at 12:57
  • @James_D will try that thanks! –  May 28 '20 at 14:45
  • A LongAdder instead of AtomicInteger or the final int[] would also work. For a better precision of the countdown timer use the ScheduledExecutorService. – 1813222 May 30 '20 at 18:08