I have a task that can be long running, and it's blocking. I must wait for this task to complete to display results on the GUI.
I know how long this task will take, so I want to notify user with a progress bar, how much time is left.
All the examples on the internet are like this:
Task<Integer> task = new Task<Integer>() {
@Override
protected Integer call() throws Exception {
int iterations;
for (iterations = 0; iterations < 1000; iterations++) {
updateProgress(iterations, 1000);
// Now block the thread for a short time, but be sure
// to check the interrupted exception for cancellation!
try {
Thread.sleep(100);
} catch (InterruptedException interrupted) {
if (isCancelled()) {
updateMessage("Cancelled");
break;
}
}
}
return iterations;
}
};
This code blocks in a loop, and update it's progress with updateProgress
method.
My case would look like:
Task<Integer> task = new Task<Integer>() {
@Override
protected Integer call() throws Exception {
try {
//This is my long running task.
Thread.sleep(10000);
} catch (InterruptedException interrupted) {
if (isCancelled()) {
updateMessage("Cancelled");
return null;
}
}
}
return iterations;
}
};
This doesn't work in a loop, so I can't update progress with updateProgress
.
One solution to this would be to create another task that would run my blocking task, and would count progress, but this seems inelegant.
Is there a better way to do this?
For these kind of requirements, I would advice you to use Infinite ProgressIndicator.
It helps to show user that some background process is taking place and when finished the ProgressIndicator will be removed.
I find it hard to see a use case in which the task blocks but you somehow know how long it would take (at least one that wouldn't be easier implemented with the animation API). But assuming you have one, I would approach it like this:
Your task is blocking, so updates to the progress must be performed elsewhere. Basically, you would want a background thread that periodically updates the progress. The optimal time to do this would be once every time a frame is rendered to the screen: the
AnimationTimer
class is designed exactly for this. So, you want the task to start an animation timer when it starts running, update the progress in thehandle(...)
method, and make sure it stops when the task stops running. This looks like:Here is a minimal test (with the above class included for convenience). Type a time in seconds in the text field and press Enter.