Swing Worker中的优雅exception处理

我通过Swing Worker类在应用程序中使用线程。 它工作正常,但我对在try-catch块中显示错误消息对话框感到不舒服。 它可能会阻止应用程序吗? 这就是它现在的样子:

SwingWorker worker = new SwingWorker() { // Executed in background thread public Void doInBackground() { try { DoFancyStuff(); } catch (Exception e) { e.printStackTrace(); String msg = String.format("Unexpected problem: %s", e .toString()); //TODO: executed in background thread and should be executed in EDT? JOptionPane.showMessageDialog(Utils.getActiveFrame(), msg, "Error", JOptionPane.ERROR_MESSAGE, errorIcon); }//END: try-catch return null; } // Executed in event dispatch thread public void done() { System.out.println("Done"); } }; 

可以使用Swing Worker框架以安全的方式完成吗? 覆盖publish()方法在这里是一个很好的领导?

编辑:

它是这样的:

 } catch (final Exception e) { SwingUtilities.invokeLater(new Runnable() { public void run() { e.printStackTrace(); String msg = String.format( "Unexpected problem: %s", e.toString()); JOptionPane.showMessageDialog(Utils .getActiveFrame(), msg, "Error", JOptionPane.ERROR_MESSAGE, errorIcon); } }); } 

调用get in done方法将导致两个try-catch块,因为计算部分抛出exception,所以我认为这最终更清晰。

一种选择是使用SwingUtilities.invokeLater(...)EDT上发布操作

 SwingUtilities.invokeLater(new Runnable(){ @Override public void run(){ JOptionPane.showMessageDialog( Utils.getActiveFrame(), msg, "Error", JOptionPane.ERROR_MESSAGE, errorIcon); } }); 

正如您所指出的, SwingWorker能够报告中间结果,但您需要覆盖在调用publish(...)时调用的process(...) publish(...)

无论如何,为什么不在发生exception时设置标志,如果设置了该标志,则在done()显示对话框,因为它在EDT安全执行?

正确的方法如下:

 SwingWorker worker = new SwingWorker() { // Executed in background thread protected Void doInBackground() throws Exception { DoFancyStuff(); return null; } // Executed in EDT protected void done() { try { System.out.println("Done"); get(); } catch (ExecutionException e) { e.getCause().printStackTrace(); String msg = String.format("Unexpected problem: %s", e.getCause().toString()); JOptionPane.showMessageDialog(Utils.getActiveFrame(), msg, "Error", JOptionPane.ERROR_MESSAGE, errorIcon); } catch (InterruptedException e) { // Process e here } } } 

您不应该尝试在后台线程中捕获exception,而是让它们传递给SwingWorker本身,然后您可以通过调用get()来获取它们,这通常会返回doInBackground()的结果( Void在你的情况下)。 如果在后台线程中抛出exception,则get()将抛出它,包含在ExecutionException

另请注意,覆盖的SwingWorker方法受到protected ,您无需public它们。

你是对的,你违反了Swing的基本规则,除了事件派遣线程之外,它不会修改任何地方的GUI。

如果是我,我会抛出一个GUI监听的事件来显示错误信息。 或者,您可以将SwingWorker的调用包装在try catch中并在那里显示对话框。

首先:对不起,简短的回答,没有太多的时间。

我遇到了同样的问题:想要从worker中发布到System.out

简短回答: 如果您使用execute()方法,它将不会阻止您的应用程序

问题是如果你按原样执行工作程序就没有阻塞:后台任务。

 class MyWorker extend SwingWorker{ @Override protected Void doInBackground() throws ... { // your logic here and a message to a stream System.out.println("from my worker, with love"); // ... try { throw new Exception("Whoops, this is an exception from within the worker"); } catch (Exception e) { System.out.println(e.getMessage()); } } } 

现在,您将调用此worker创建一个新实例,然后调用execute()方法。 但是为了节省你一些时间:你可能想知道你的工作完成的时间,所以你需要注册一个属性更改监听器,这很简单:

 class MyListener implements PropertyChangeListener{ @Override public void propertyChange(PropertyChangeEvent evt){ if(evt.getPropertyName().equals("state") && evt.getNewValue().equals(SwingWorker.StateValue.DONE)){ System.out.println("The worker is done"); } } } 

并将所有内容放在main()

 public void main(...){ MyWorker w = new MyWorker(); MyListener l = new MyListener(); w.addPropertyChangeListener(l); w.execute(); }