Tarefa de fundo periódica do JavaFX

Eu tento executar em thread de plano de fundo do aplicativo JavaFX periodicamente, que modifica alguma propriedade GUI.

Acho que sei como usar as classs Task e Service do javafx.concurrent e não consigo descobrir como executar essa tarefa periódica sem usar o método Thread#sleep() . Seria bom se eu pudesse usar algum Executor de Executors fabricar methods ( Executors.newSingleThreadScheduledExecutor() )

Eu tentei executar Runnable cada 5 segundos, o que reinicia javafx.concurrent.Service mas ele trava imediatamente como service.restart ou mesmo service.getState() é chamado.

Então, finalmente eu uso o Executors.newSingleThreadScheduledExecutor() , que triggers o meu Runnable cada 5 segundos e que o Runnable executa outro Runnable usando:

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

Parece muito desagradável 🙁 Existe uma maneira melhor de fazer isso usando Task ou classs de Service ?

   

Você pode usar Timeline para o que importa:

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

para processos em segundo plano (que não fazem nada para a interface do usuário), você pode usar o bom java.util.Timer antigo:

 new Timer().schedule( new TimerTask() { @Override public void run() { System.out.println("ping"); } }, 0, 5000); 

Eu preferiria a PauseTransition:

  PauseTransition wait = new PauseTransition(Duration.seconds(5)); wait.setOnFinished((e) -> { /*YOUR METHOD*/ wait.playFromStart(); }); wait.play(); 

Aqui está uma solução usando o Java 8 e o ReactFX . Digamos que você queira periodicamente recomputar o valor de Label.textProperty() .

 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 getStatusAsync() { return CompletableFuture.supplyAsync(() -> getStatusFromNetwork()); } String getStatusFromNetwork() { // ... } 

Comparado com a solução do Sergey, você não dedica todo o encadeamento a obter status da rede, mas usa o conjunto de encadeamentos compartilhado para isso.