I've found a lot of suggestions to use Timeline
with KeyFrame.onFinished
to schedule tasks in the JavaFX. But the AnimationTimer
doc says, that its handle
method is called 60 times per second.
It is unclear from documentation but it seems that Timeline
uses AnimationTimer
internally. Does that means that the timeline solution for scheduling imposes CPU-intensive polling mode? If that is actually how JavaFX works, what other methods for scheduling is recommended?
Advised Usage Rules for Scheduling in JavaFX
Given how Timeline works (see below), some basic rules can be derived:
Use a Timeline when you want to schedule quick operations that modify attributes of the scene graph.
Do not use a Timeline when you want to do any of the following:
Also, for a one-off execution that updates the scene graph after a fixed delay, I like to use a PauseTransition.
Answers to specific questions and concerns
It is unclear from documentation but it seems that Timeline uses AnimationTimer internally.
No, Timeline does not use AnimationTimer internally. However, Timeline is still pulse based and will receive code to update the current state of the timeline will be invoked on each pulse (usually 60 times a second). To understand what a pulse is read the background section below.
Does that means that the timeline solution for scheduling imposes CPU-intensive polling mode?
Yes, there is some overhead, but it is likely minimal enough that it can be disregarded. The JavaFX system is going to be running some work on each pulse anyway, regardless whether you create any timelines yourself. Unless you are heavily animating objects or doing a lot of work on each pulse, then the time to process each pulse will be completely trivial as there is simply very little work to be done on each pulse.
If that is actually how JavaFX works, what other methods for scheduling is recommended?
There are numerous alternatives to Timeline:
If you do use something other than a timeline, you need to take care:
Background Info
Timeline Operation
For example, let's say you have a Timeline which has a Keyframe that has a duration of 1 second. The internal Timeline will still be updated each pulse. This is required because a Timeline is more than just a scheduler, it has other properties and tasks. For instance the Timeline has a currentTime property. The currentTime will be updated each pulse, so that it always reflects the current time accurately. Similarly, internal logic with the Timeline will check to see if there are any KeyValues associated with the Timeline, and update their values on each pulse, in accordance with their associated Interpolator. And the internal logic will check on each pulse to see if the Timeline is finished, to call the onFinished handler. It will also evaluate the current time versus the duration of each keyframe and, if there is a match, fire the appropriate action event for the keyframe.
So the Timeline is acting like a scheduler in that it can execute key frames at specific times, but it is more than a scheduler as it also maintains it's current time, current state and ability to continuously vary associated key values. Additionally, you can vary the rate, direction and number of cycles of a timeline, as well as pause it in position, then resume it, which also differs from a traditional scheduler.
An aspect of the Timeline is that because it is based upon callbacks from pulses in the JavaFX system; everything runs on the JavaFX application thread. Therefore, when you use timelines (even 1000 of them), no additional threads are spawned, so from that perspective it is lightweight. Also all logic invoked by the timeline occurs on the JavaFX application thread. Because everything runs on the JavaFX application thread, this makes the Timeline nice for manipulating elements and attributes of the active JavaFX scene graph (such manipulations must be performed on the JavaFX application thread). However, a timeline would be a bad choice if you wanted to do a lot of CPU time-consuming work or blocking I/O in the associated timeline keyframes. This is because the JavaFX application thread will be blocked while that work occurs, freezing your UI.
Pulses
The JavaFX runtime system is based upon pulses.
A pulse is an event that indicates to the JavaFX scene graph that it is time to synchronize the state of the elements on the scene graph with Prism. A pulse is throttled at 60 frames per second (fps) maximum and is fired whenever animations are running on the scene graph. Even when animation is not running, a pulse is scheduled when something in the scene graph is changed. For example, if a position of a button is changed, a pulse is scheduled.
When a pulse is fired, the state of the elements on the scene graph is synchronized down to the rendering layer. A pulse enables application developers a way to handle events asynchronously. This important feature allows the system to batch and execute events on the pulse.
The JavaFX animation system stores a list of all of the animations and animation timers which been created and not garbage collected. On each pulse it will iterate through this list. Each animation timer will have it's handle callback invoked on each pulse. Each timeline or transition will similarly have its internal state update and update any associated key values or fire key frame action events as appropriate.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With