Can I cancel a Swingworker
and wait for it to complete before running background task? Or alternatively, can I send an interrupt to a task that runs the code in doInBackground()
without cancelling the whole swing worker.?
My problem is I do not want the code in done()
to start before the code in doInBackground()
has completed. Earlier code never called cancel on the Swingworker
instead I just set a volatile boolean that the WidgetController
would check and if set closedown gracefully. This all worked fine except the WidgetController
sometimes took to long to check this flag, so I need to be able use the interrupt method.
Pseudo Example
A dialog is displayed when user clicks start this invokes WidgetDialogListener
this creates instance of WidgetWorker
, this starts WidgetController
, displays a WidgetProgressDialog
and on normal completion of WidgetController
displays ShowWidgetReport
showing a summary of what WidgetController
did.
Whilst the WidgetController
is running, the WidgetProgressDialog
is displayed showing progress. If the user clicks on the cancel button to stop progress this causes an interrupt to be sent to WidgetController
then without waiting for widgetcontroller
to actually complete the done method gets called causing ShowWidgetReport
to display. But I don't want it to do this until WidgetController
has actually completed.
class WidgetDialogListener implements ActionListener
{
public WidgetDialogListener()
{
}
public void actionPerformed(ActionEvent e)
{
StartFixSongsDialog.this.dispose();
WidgetProgressDialog wpd = new FixSongsDialog();
wpd.setVisible(true);
WidgetWorker ww = new WidgetWorker();
wpd.setSwingWorker(ww);
Executors.newSingleThreadScheduledExecutor().submit(ww);
}
}
class WidgetProgressDialog
{
....................
private void actionPerformed(ActionEvent e)
{
//Main.stopTask();
swingWorker.cancel(true);
}
}
class WidgetWorker extends SwingWorker<String, Object>
{
@Override
public String doInBackground() throws Exception
{
new WidgetController().startCreateWidgets();
return "";
}
@Override
protected void done()
{
ShowWidgetReport showReport = new ShowWidgetReport();
showReport.setVisible(true);
}
}
Edit
I used the AwaitingWorker
described at Waiting for a cancelled future to actually finish that Jacob pointed me to
abstract class AwaitingWorker<T, V> extends SwingWorker<T, V>
{
private final CountDownLatch actuallyFinishedLatch = new CountDownLatch(1);
protected abstract T performOperation() throws Exception;
@Override
protected final T doInBackground() throws Exception
{
try
{
return performOperation();
}
finally
{
actuallyFinishedLatch.countDown();
}
}
public void awaitActualCompletion() throws InterruptedException
{
actuallyFinishedLatch.await();
}
}
class WidgetWorker extends AwaitingWorker<String, Object>
{
@Override
public String performOperation() throws Exception
{
new WidgetController().startCreateWidgets();
return "";
}
@Override
protected void done()
{
try
{
awaitActualCompletion();
}
catch(InterruptedException ioe)
{
}
ShowWidgetReport showReport = new ShowWidgetReport();
showReport.setVisible(true);
}
}
Maybe have misunderstood exactly the solution but it seems whichever way you do it a gui thread ends up waiting for a non-gui task to finish, whereas what I want I want is for the non-gui task to complete before anything is done on the gui thread.