How can I read the result of SwingWorker * without waiting for the download?

I am writing an application that performs file menu actions using SwingWorker . Each method invoked returns a boolean value indicating whether the operation was successful or not.

I am currently using result expectation, for example:

 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 intensive way of polling?

Using worker.get() will not work directly, since it blocks EDT, waiting for the task to complete - this means that even the dialogs that I open from SwingWorker will not be painted.

EDIT: if possible, I would like to avoid the method (or the worker) reporting their result asynchronously. I execute several short methods (file -> open, new, close, save, save as, exit) that rely on each other (i.e. when trying to exit, close calls close, close can cause save, save can cause save to form). Solving this asynchronously makes the code much more complex.

+6
source share
5 answers

The point of SwingWorker is to run some task in the background and not block the EDT. Either you want something synchronously and the EDT will be blocked, which you try, or you want something asynchronous, and the background task should update its status using the publish SwingWorker method.

You can display a blocking mod dialog box with a progress bar during the execution of the task and hide it after the task is completed.

An alternative is to block for some time, hoping that the task will be completed quickly, and then back up to the asynchronous execution method. This can be done using the get method , which takes a timeout as an argument.

+6
source

You can use the asynchronous paradigm. Look at Observer / Observable and use the task to pass the result back to the object that is currently polling.

+4
source

Using worker.get() will not work directly, since it blocks EDT, waiting for the task to complete - this means that even the dialogs that I open from SwingWorker will not be painted.

They are also not with the current code. Your busy wait blocks EDT just like calling worker.get() - there is only one thread for sending events, and dialogs in SwingWorker block if this thread rotates in a loop or expects blocking. The problem here is that if the method runs on EDT, it simply cannot return the value from the asynchronous operation (without binding the EDT) to its caller.

The correct way to respond to completed asynchronous processing overrides the done() method in SwingWorker .

Also check out http://java.sun.com/products/jfc/tsc/articles/threads/threads2.html for more information.

+4
source

One way mentioned by a few people above is to override the SwingWorker method. However, if for some reason you need SwingWorker code to write outside of SwingWorker and in the calling code, you can use the support for changing SwingWorker properties. Just add a PropertyChangeListener to SwingWorker and listen for the state property, which has the name of the state property. You can then retrieve the SwingWorker state using the getState () method. When this is done, it will return a DONE value for the SwingWorker.StateValue enumeration. For example (from the answer I gave 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(); } } 
+4
source

I had a similar problem when I wanted a function to return a value that would be calculated in a swing worker. I did not want to just get this thread to block EDT. I also did not want it to block. So I used the semaphore as follows:

 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 think this is not ideal for all situations. But I thought it was an alternative approach, which is very useful to me.

0
source

Source: https://habr.com/ru/post/896858/


All Articles