I'm using a thread to periodically run a three second background animation.
I adapted the code in question from a Thread Demo example written in Swing and used
it to replace a not quite working earlier version that used both a thread and a task.
My program stops/suspends the thread when either playing a video or running an animation and starts a new thread when ending the video or animation. This seems to work without any downside which is why I'm puzzled why my earlier JavaFX searches hadn't turned up a similar solution to the one I'm using. It seems a rather direct approach for running short, simple background animations.
Where am I going wrong with this? What am I missing? How would I rewrite this code using both a Thread and a Task or do I need to?
I should add - the while and run statements are virtually unchanged from the original and the only significant addition to the Swing code was to add thread.setDaemon( true ) to startThread().
A podcast listener.
// background thread
class BackGround extends Thread {
@Override
public void run() {
while ( suspend.getValue() == false ) {
try {
int r = shared.randInt( 5, 10 );
Thread.sleep( r * 1000 );
} catch ( InterruptedException e ) {
// do nothing
}
if ( suspend.getValue() == false ) {
Platform.runLater( () -> {
int g = shared.cssGradients.length - 1;
g = shared.randInt( 0, g );
gradientColor.set( shared.cssGradients[g] );
Boolean bif = shared.updatePanes( shared.cssGradients[g],
leftPane, rightPane );
});
}
}
}
} // class background
// start thread
public synchronized void startThread() {
thread = new BackGround(); // Thread thread ...defined elsewhere
thread.setDaemon( true );
thread.start();
}
// stop thread
public synchronized void stopThread() {
suspend.set( true );
}
The reason the Task
class is useful for JavaFX is that it provides a number of callbacks like succeeded()
, failed()
or cancelled()
and methods like updateProgress()
and updateMessage()
that will run in the JavaFX Application thread and therefore let you update the UI without Platform.runLater( () -> { ... });
This makes the Task
class a perfect choice for doing background tasks like downloading data or long running computations.
However, since your thread simply runs continuously without ever really finishing its work, it doesn't seem that you would need any of the additional functionality a Task
would provide you with over a simple Thread
.
Still, if you really wanted to convert your code to use a Task
, it would look just like this:
class BackGround extends Task<Void> {
@Override
protected Void call() throws Exception {
while (suspend.getValue() == false) {
try {
int r = shared.randInt(5, 10);
Thread.sleep(r * 1000);
} catch (InterruptedException e) {
// do nothing
}
if (suspend.getValue() == false) {
Platform.runLater(() -> {
int g = shared.cssGradients.length - 1;
g = shared.randInt(0, g);
gradientColor.set(shared.cssGradients[g]);
Boolean bif = shared.updatePanes(shared.cssGradients[g],
leftPane, rightPane);
});
}
}
return null;
}
}
// start thread
public synchronized void startThread() {
Task<Void> bg = new BackGround();
Thread taskThread = new Thread(bg);
taskThread.setDaemon(true);
taskThread.start();
}
// stop thread
public synchronized void stopThread() {
suspend.set( true );
}
As you see, it really doesn't make a difference for you, as you don't need anything that a Thread
couldn't give you. If however you wanted to have closer communication with the UI thread, e.g. showing a progress bar or showing status updates, then a Task
would give you the tools to do that.
I guess its also worth mentioning that the use of a Timeline
would be quite elegant for triggering your animations. It would look somewhat like this:
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
int g = shared.cssGradients.length - 1;
g = shared.randInt(0, g);
gradientColor.set(shared.cssGradients[g]);
Boolean bif = shared.updatePanes(shared.cssGradients[g], leftPane, rightPane);
}
}
));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
The code inside the handle()
method is run every second in the JavaFX Application thread. Unfortunately this only lets you set a fixed time between executions, while you seem to want to wait a random amount of time each time.
TL;DR: Using a Thread
is ok, because you don't need the additional functionalities of a Task
in your use case.
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