Reputation: 105
I am writing an application on javaFX and as a part of my view(in MVVM architecture) I am using an FXML Label for the status of my application to present for the client(for example: if a file was uploaded successfully or not).
I want to clean this status label a few seconds after an update was made.
I used this code to run a thread to do so but the problem occurs when more than one update was made before the previous finished its job.
I thought of canceling any previous threads in the thread-pool before executing a new thread but I didn't find a way to do so.
public class MainWindowController implements Observer {
ViewModel vm;
ScheduledExecutorService scheduledExecutorService;
Stage stage;
@FXML
Label appStatus;
public void loadProperties(){
FileChooser fc = new FileChooser();
fc.setTitle("Load Project Properties");
fc.setInitialDirectory(new File("./resources"));
FileChooser.ExtensionFilter extensionFilter = new FileChooser.ExtensionFilter(
"XML Files (*.xml)", "*.xml");
fc.getExtensionFilters().add(extensionFilter);
File chosenFile = fc.showOpenDialog(stage);
//CONTINUE HERE
if(chosenFile==null){
appStatus.setTextFill(Color.RED);
vm.appStat.setValue("Failed to load resource");
}
else{
vm.setAppProperties(chosenFile.getAbsolutePath());
}
cleanStatusBox();
}
public void cleanStatusBox(){
scheduledExecutorService.schedule(new Runnable() {
@Override
public void run() {
Platform.runLater(()->vm.appStat.setValue(""));
}
},10000, TimeUnit.MILLISECONDS);
}
public void setViewModel(ViewModel vm) {
this.vm = vm;
scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
appStatus.textProperty().bind(vm.appStat);
}
}
Upvotes: 0
Views: 526
Reputation: 209408
A ScheduledExecutorService
(and using background threads in general) is far too heavy-handed an approach for this.
Instead, consider using a PauseTransition
, which once started will execute its onFinished
handler on the JavaFX Application Thread after the specified time. The playFromStart()
method "restarts" the pause, enabling multiple updates without conflict.
public class MainWindowController implements Observer {
ViewModel vm;
PauseTransition clearLabelPause;
Stage stage;
@FXML
Label appStatus;
public void loadProperties(){
FileChooser fc = new FileChooser();
fc.setTitle("Load Project Properties");
fc.setInitialDirectory(new File("./resources"));
FileChooser.ExtensionFilter extensionFilter = new FileChooser.ExtensionFilter(
"XML Files (*.xml)", "*.xml");
fc.getExtensionFilters().add(extensionFilter);
File chosenFile = fc.showOpenDialog(stage);
//CONTINUE HERE
if(chosenFile==null){
appStatus.setTextFill(Color.RED);
vm.appStat.setValue("Failed to load resource");
}
else{
vm.setAppProperties(chosenFile.getAbsolutePath());
}
clearLabelPause.playFromStart();
}
public void setViewModel(ViewModel vm) {
this.vm = vm;
clearLabelPause = new PauseTransition(Duration.seconds(10));
clearLabelPause.setOnFinished(e -> vm.appStat.setValue(""));
appStatus.textProperty().bind(vm.appStat);
}
}
Upvotes: 3
Reputation: 44150
The schedule
method returns a ScheduledFuture
which has a cancel
method. You are currently discarding that.
Attempts to cancel execution of this task. This attempt will fail if the task has already completed, has already been cancelled, or could not be cancelled for some other reason. If successful, and this task has not started when cancel is called, this task should never run. If the task has already started, then the
mayInterruptIfRunning
parameter determines whether the thread executing this task should be interrupted in an attempt to stop the task.After this method returns, subsequent calls to
isDone()
will always return true. Subsequent calls to isCancelled() will always return true if this method returned true.
In your case, if the task hasn't started then it will be removed from the queue of tasks, and it will be as if you never scheduled it.
If the task is currently running then you will not be able to cancel it, since you do not check the thread's interrupt flag. Whether you pass true or false to cancel()
will not make a difference.
All your task does is push a task onto another thread, so the scheduled executor task is likely to be extremely quick. Because of that, it doesn't really matter that you don't check the interrupt flag. For longer running tasks which involve more steps - do X, then Y, then Z - then it would be important to check the flag.
Upvotes: 2