JavaFX Intermittent Background Task

I am trying to run the background thread of a JavaFX application periodically, which changes some GUI properties.

I think I know how to use the Task and Service classes from javafx.concurrent and cannot figure out how to run such a periodic task without using the Thread#sleep() method. It would be nice if I could use some of the methods Executor from Executors ( Executors.newSingleThreadScheduledExecutor() )

I tried to run Runnable every 5 seconds, which restarts javafx.concurrent.Service , but it hangs immediately when service.restart or even service.getState() called.

So, I use Executors.newSingleThreadScheduledExecutor() , which runs my Runnable every 5 seconds and that Runnable starts another Runnable using:

 Platform.runLater(new Runnable() { //here i can modify GUI properties } 

This looks very unpleasant :( Is there a better way to do this using Task or Service classes?

+57
javafx-2
Apr 01 2018-12-12T00:
source share
4 answers

You can use Timeline in this regard:

 Timeline fiveSecondsWonder = new Timeline(new KeyFrame(Duration.seconds(5), new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { System.out.println("this is called every 5 seconds on UI thread"); } })); fiveSecondsWonder.setCycleCount(Timeline.INDEFINITE); fiveSecondsWonder.play(); 

for background processes (which do nothing with the user interface) you can use the good old java.util.Timer :

 new Timer().schedule( new TimerTask() { @Override public void run() { System.out.println("ping"); } }, 0, 5000); 
+95
Apr 01 2018-12-12T00:
source share
— -

I would prefer to use PauseTransition:

  PauseTransition wait = new PauseTransition(Duration.seconds(5)); wait.setOnFinished((e) -> { /*YOUR METHOD*/ wait.playFromStart(); }); wait.play(); 
+12
Jan 08 '16 at 15:57
source share

Here is a solution using Java 8 and ReactFX . Say you want to recalculate the value of Label.textProperty() periodically.

 Label label = ...; EventStreams.ticks(Duration.ofSeconds(5)) // emits periodic ticks .supplyCompletionStage(() -> getStatusAsync()) // starts a background task on each tick .await() // emits task results, when ready .subscribe(label::setText); // performs label.setText() for each result CompletionStage<String> getStatusAsync() { return CompletableFuture.supplyAsync(() -> getStatusFromNetwork()); } String getStatusFromNetwork() { // ... } 

Compared to Sergey’s decision, you don’t devote the entire thread to receiving status from the network, but instead use the common thread pool for this.

+7
Jun 03 '14 at 22:39
source share

You can also use ScheduledService . I use this alternative, noticing that while using Timeline and PauseTransition , the user interface hangs in my application, especially when the user interacts with MenuBar elements (in JavaFX 12). When using ScheduledService these problems no longer occurred.

 class UpdateLabel extends ScheduledService<Void> { private Label label; public UpdateLabel(Label label){ this.label = label; } @Override protected Task<Void> createTask(){ return new Task<Void>(){ @Override protected Void call(){ Platform.runLater(() -> { /* Modify you GUI properties... */ label.setText(new Random().toString()); }); return null; } } } } 

And then use it:

 class WindowController implements Initializable { private @FXML Label randomNumber; @Override public void initialize(URL u, ResourceBundle res){ var service = new UpdateLabel(randomNumber); service.setPeriod(Duration.seconds(2)); // The interval between executions. service.play() } } 
+2
Jun 06 '19 at 20:58 on
source share



All Articles