I have a SwingWorker class whose doInBackground executes queries on a remote database. I invoke publish(true) which sets setVisible to true for the JDialog holding a loader animation.
Everything is working fine as expected:
Background method starts.
JDialog modal is shown.
Background method completes.
JDialog is hidden/disposed in done() method.
UI is updated with database values.
However, when I point my application to the database running on my local machine the JDialog is shown but never closed/disposed even though the done() was called. This halts execution of UI code in the done method as well not until I manually close the loader dialog.
This odd behaviour is as follows:
Background method starts.
JDialog modal is shown.
Background method completes.
JDialog is NOT hidden/disposed in done() method.
UI is NOT updated
I must mention that execution over the remote database takes 10 seconds or more but a split second on my local database. How is the faster speed causing this odd behaviour?
Below is my code snippet:
new SwingWorker<Void, Boolean>() {
JDialog loader = new MyDialogLoader();
#Override
protected Void doInBackground() {
publish(true);
//DATABASE EXECUTION CODE IS HERE
publish(false);
return null;
}
#Override
protected void process(List<Boolean> chunks) {
for (Boolean val : chunks) {
loader.setVisible(val);
}
}
#Override
protected void done() {
loader.dispose();
//UI UPDATE WITH DATABASE VALUES CODE HERE;
}
}.execute();
Probably there is an Exception being thrown in doBackground(), so publish(false) is not being executed. Maybe an error accessing the database...
The Exceptions thrown by doBackground are silently caught and saved by the SwingWorker. The way to check if such an Exception was thrown, is to call the get() method in the done() method. It will throw an ExecutionException having the original exception as cause:
#Override
protected void done() {
loader.dispose();
try {
get();
} catch (ExecutionException ex) {
ex.printStackTrace();
// some message or what ever using ex.getCause()
} catch (InterruptedException ex) {
ex.printStackTrace();
// TODO
}
//UI UPDATE WITH DATABASE VALUES CODE HERE;
}
I am sharing this as the answer because it has solved the issue.
I did away with publish and process methods; the loader JDialog is now made visible from doInBackground. To ensure this UI interaction is performed on the Event Dispatch Thread, the statement is placed inside SwingUtilities.invokeLater.
new SwingWorker<Void, Void>() {
JDialog loader = new MyDialogLoader();
#Override
protected Void doInBackground() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
loader.setVisible(true);
} catch (Exception e) {
e.printStackTrace()
}
}
});
//DATABASE EXECUTION CODE IS HERE
return null;
}
#Override
protected void done() {
loader.dispose();
//UI UPDATE WITH DATABASE VALUES CODE HERE;
}
}.execute();
Related
I have a "little" issue with Service usage.
The code below doesn't work: text value isn't updated in HMI but its value is correct !!?
public class FilterController
{
#FXML
private TextField totalItemCount;
private final Service service = new Service() {
#Override
protected Task createTask()
{
return new Task<Void>() {
#Override protected Void call() throws Exception {
int x = (int) (Math.random() * 10000);
System.out.println("x = " + x);
try {
totalItemCount.setText(Integer.toString(x));
System.out.println("totalItemCount = " + totalItemCount.getText());
}
catch (Throwable ex)
{
System.err.println("Fail");
ex.printStackTrace();
}
return null;
}
};
}
#Override
protected void failed()
{
super.failed();
System.err.println("FAILED");
}
};
#FXML
public void handleFindProblemsEvent()
{
System.out.println("Handle Find Problems");
service.restart();
}
}
I don't have any error. Fail message isn't displayed, so I can think that job has been done but it's not the case.
Is it a bug or a bad usage ?
Thanks for your help.
Note: I use jre1.8.0_25
JavaFX is a single thread GUI toolkit, so every update of a GUI component has to be done on the main application (JavaFX) thread.
What you are doing there, is trying to update a TextField from a background thread and an IllegalStateException will get thrown.
The Task and Service classes are meant to compute something in the background and do a GUI update afterwards.
Like explained over here and over here, you should create a Task<Integer> and return the computed value. If this succeeds, you can retrieve the value in the succeeded() method with getValue() and set the value to the TextField.
The succeeded() method is getting called from the GUI Thread, so its safe to update the TextField here.
You have not called the failed() method anywhere.
I assume you Task is executed in its own thread so you need to sync calls to fx APIs with Platform.runLater
I was reading AsyncTask.java and there are few places that I can't understand.
What does this code actually do? Judging by the comment it should create the handler, but I can't get how it can do this. The method getLooper() in the Handler class just returns the handler, so there is no way I can see it can initialize a new handler.
/** #hide Used to force static handler to be created. */
public static void init() {
sHandler.getLooper();
}
Why putting postResultIfNotInvoked() in the overriden done() method? How can it be not invoked? If I understand this right, first the call() method of mWorker will be called and then mTaskInvoked is guaranteed to be true.
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
//...
return postResult(doInBackground(mParams));
}
};
mFuture = new FutureTask<Result>(mWorker) {
#Override
protected void done() {
try {
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
init() isn't really used in regular code.
It can be used in platform test code - calling it first makes the class loader initialize the static members on the current thread. It's useful to making sure the Handler is created on the main UI thread while tests run on a background thread for example.
Because of #hide, it's not usable in code written with SDK's stub version of android.jar.
This is there to fix a bug to make sure onCancelled() is called if cancel() is called early.
I'm using Eclipse jobs API for the first time. I have a plugin that needs to call a method from a jar file to process large data, so I need to show a progress dialog. My question is, how can I update the progress dialog with the number of data items that had been processed? right now I have this code
Job job = new Job("Annotate"){
protected IStatus run(IProgressMonitor monitor){
monitor.beginTask("Annotation..", annotate.getTotal());
annotate.annotateData();
monitor.done();
Display.getDefault().asyncExec(new Runnable() {
public void run() {
try {
SaveUtils.saveEntry(wizard.getEntry(), AnnotationEntry);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
return Status.OK_STATUS;
}
};
job.setUser(true);
job.schedule();
annotate object has a method that return the number of the data items that had been processed, but I don't know how let the progress dialog talk to the annotate object. Please help with thoughts or examples.
You would call monitor.worked() enough times with a sum of parameters to match the amount of work you said would be needed with annotate.getTotal(). Note that if you're doing your work on the UI thread as shown, you won't see updates all that smoothly--they require the UI thread, too.
If your long running method does not provide a way to find out about progress then the best you could do would be to run the method in a separate thread and have the Job update the progress monitor periodically and stop when the thread terminates.
I found a solution to this tricky problem. Here are the steps:
I created an interface inside my annotation package called IControlProgressDialog with a method void setCurrentIndex();
in the method annotateData I added a parameter of type IControlProgressDialog.
inside the loop that iterates over my data items I called the setCurrentIndex();
I created a class inside my plugin called ImplControlProgressDialog that implements that interface and it defines an object reference of type IProgressMonitor.
in the ImplControlProgressDialog I implemented the method setCurrentIndex() as
void setCurrentIndex(){
monitor.worked(1);
}
This gave me the ability to update the progress dialog while the annotate.annotateData() is running on another thread.
The updated code of my job:
Job job = new Job("Annotate"){
protected IStatus run(IProgressMonitor monitor){
monitor.beginTask("Annotation..", annotate.getTotal());
ImplControlProgressDialog control = new ImplControlProgressDialog (monitor);
annotate.annotateData(control);
monitor.done();
Display.getDefault().asyncExec(new Runnable() {
public void run() {
try {
SaveUtils.saveEntry(wizard.getEntry(), AnnotationEntry);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
return Status.OK_STATUS;
}
};
job.setUser(true);
job.schedule();
I have some code which executes a download in a separate thread, created so that the JFrame GUI will continue to update during the download. But, the purpose is completely defeated when I use Thread.join(), as it causes the GUI to stop updating. I need a way to wait for the thread to finish and still update the GUI.
You can have the task that does the download also fire an event to the GUI.
For example:
Runnable task = new Runnable() {
public void run() {
// do your download
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// call some method to tell the GUI that the download finished.
}
});
}
};
and then to run it, either use an Executor (preferred method) or a raw thread:
executor.execute(task);
or
new Thread(task).start();
As pointed out in the comments, you'd generally use a SwingWorker to do this kind of thing but you can also do the manual approach outlined above.
SwingWorker provides a doInBackground method where you would stick your download logic in, a done method where you would stick in code to notify the GUI that the download finished and a get method to get the result of doInBackground (if there was one).
E.g.,
class Downloader extends SwingWorker<Object, Object> {
#Override
public Object doInBackground() {
return doDownload();
}
#Override
protected void done() {
try {
frame.downloadDone(get());
} catch (Exception ignore) {
}
}
}
(new Downloader()).execute();
I'm writing an application that executes its file menu actions using SwingWorker. Every called method returns a boolean value that tells, whether the operation was successfully executed or not.
At the moment I'm using busy waiting for the result, like this:
public boolean executeOperation() {
final SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {
#Override
protected Boolean doInBackground() throws Exception {
// ..
if (aborted) {
return false;
}
// ..
return true;
}
};
worker.execute();
// busy wait
while (!worker.isDone())
;
try {
return worker.get().booleanValue();
} catch (Exception e) {
// handle exceptions ..
return false;
}
}
Is there a less polling-intense way of solving this?
Using worker.get() directly wouldn't work, as it blocks the EDT, waiting for the task to finish - meaning even the dialogs I open from within the SwingWorker wouldn't get painted.
EDIT: If possible, I would like to avoid that the method (or the worker) to communicate their result asynchronously. I'm implementing several short methods (file -> open, new, close, save, save as, exit) that rely on each other (i. e. when the trying to exit, exit calls close, close might call save, save might call save as). Solving this asynchronously seems to make the code much more complicated.
The point of the SwingWorker is precisely to launch some task in the background and don't block the EDT. Either you want something synchronous, and the EDT will be blocked whatever you try, or you want something asynchronous, and the background task should update its status using the publish method of the SwingWorker.
You could display a blocking modal dialog with a progress bar while the task is running, and hide it once the task completes.
The alternative is to block for some time, hoping the task will be quick to finish, and then backup to an asynchronous way of doing. This can be done using the get method taking a timeout as argument.
You could use an asynchronous paradigm. Look at Observer / Observable and use the job to transfer the result back to the object which is currently doing the polling.
Using worker.get() directly wouldn't work, as it blocks the EDT, waiting for the task to finish - meaning even the dialogs I open from within the SwingWorker wouldn't get painted.
They don't with the current code either. Your busy wait blocks the EDT as much as calling worker.get() does - there is only one event dispatch thread, and the dialogs in the SwingWorker are just as blocked if that thread is spinning in a loop or awaiting a lock. The problem here is that if a method runs on the EDT, it simply can't return a value from an asynchronous operation (without hogging the EDT) to its caller.
The correct way to react to completed async processing is overriding the done() method in SwingWorker.
Also check out http://java.sun.com/products/jfc/tsc/articles/threads/threads2.html for more info.
One way as mentioned by several folks above is to override the SwingWorker's done method. However if for some reason you want the post SwingWorker code outside of the SwingWorker and in the calling code, you can take advantage of SwingWorker's property change support. Simply add a PropertyChangeListener to the SwingWorker and listen for the state property which has a property name of "state". You can then extract the SwingWorker's state with its getState() method. When it is done it will return the DONE value of the SwingWorker.StateValue enum. For example (from an answer I've given in another thread here on SO):
if (turn == white) {
try {
final SwingWorker<Move, Void> mySwingWorker = new SwingWorker<Move, Void>() {
#Override
protected Move doInBackground() throws Exception {
Engine e = new Engine(); // Engine is implemented by runnable
e.start();
Move m = e.getBestMove(board);
return m;
}
};
mySwingWorker.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (StateValue.DONE == mySwingWorker.getState()) {
try {
Move m = mySwingWorker.get();
// TODO: insert code to run on the EDT after move determined
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
});
mySwingWorker.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
I ran into a similar problem when I wanted a function to return a value that would be calculated in a swing worker. I didn't want to simply get that thread to block the EDT. I also didn't want it to block. So I used a semaphore like this:
public boolean executeOperation() {
final Semaphore semaphore = new Semaphore(1);
semaphore.acquire(1); // surround by try catch...
final SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {
#Override
protected Boolean doInBackground() throws Exception {
// ..
if (aborted) {
semaphore.release();
return false;
}
// ..
semaphore.release();
return true;
}
};
worker.execute();
try {
semaphore.tryAcquire(1, 600, TimeUnit.SECONDS); // awakes when released or when 10 minutes are up.
return worker.get().booleanValue(); // blocks here if the task doesn't finish in 10 minutes.
} catch (Exception e) {
// handle exceptions ..
return false;
}
}
I guess this is not ideal for all situations. But I thought it was an alternative approach that was very useful for me.