Swing Worker中的优雅异常处理

fbi*_*jec 23 java swing exception-handling

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

SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {

    // 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");
    }
};
Run Code Online (Sandbox Code Playgroud)

可以使用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);

        }
    });

}
Run Code Online (Sandbox Code Playgroud)

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

jfp*_*ret 62

正确的方法如下:

SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
    // 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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

你不应该尝试在后台线程中捕获异常,而是让它们传递给SwingWorker本身,然后你可以done()通过调用get()通常调用返回结果doInBackground()(Void在你的情况下)来获取它们.如果在后台线程中抛出异常,则get()抛出它,包裹在一个内部ExecutionException.

请注意,覆盖的SwingWorker方法是protected,您不需要制作它们public.

  • 然后在这种情况下,我们可能想知道为什么你使用`SwingWorker`并且不使用你自己的线程进行后台工作,因为你没有使用任何相关的`SwingWorker`功能.另请注意,您的代码不会处理后台线程的中断. (2认同)

mre*_*mre 13

一种选择是用来SwingUtilities.invokeLater(...)发布动作EDT

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

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

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

  • 在done()方法中处理它正是我过去接近这种情况的方式.invokeLater也是一个很好的解决方案. (4认同)