【问题标题】:Error handling in SwingWorkerSwingWorker 中的错误处理
【发布时间】:2013-12-13 15:13:30
【问题描述】:

我的问题是基于理论的问题,但它确实满足了我的特定需求。

当您的 SwingWorker 抛出一个您 a) 可以预期并且 b) 需要从中恢复并继续的异常时,您会怎么做,但您想通知用户此错误已发生? 如何您是否在不违反“No Swing code from doInBackground()”的情况下抓住预期的异常并通知用户?

考虑到这个问题,我开发了一个 SSCCE,我想提出以下问题。

SSCCE:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.ExecutionException;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

public class Test {

    public static void main(String args[]) {
        final JFrame frame = new JFrame();
        JButton go = new JButton("Go.");
        go.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                new Task(frame);
            }
        });
        frame.add(go);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    static class Task extends SwingWorker<Void, Void> {
        JFrame parent;
        JDialog dialog;
        public Task(JFrame parent) {
            this.parent = parent;
            dialog = new JDialog(parent);
            JProgressBar jpb = new JProgressBar();
            jpb.setIndeterminate(true);
            dialog.add(jpb);
            dialog.setLocationRelativeTo(null);
            dialog.setVisible(true);
            execute();
        }

        @Override
        protected Void doInBackground() throws Exception {
            for(int i = 0; i < 100000; i++) {
                System.out.println(i);
                try {
                    if(i == 68456) throw new IllegalStateException("Yikes! i = 68456.");
                } catch (final IllegalStateException e) {
                    SwingUtilities.invokeAndWait(new Runnable() {
                        @Override
                        public void run() {
                            JOptionPane.showMessageDialog(parent, "Error: " + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
                        }
                    });
                }
            }
            return null;
        }

        @Override
        protected void done() {
            if (!isCancelled()) {
                try {
                    get();
                } catch (ExecutionException | InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("done");
            dialog.dispose();
        }

    }
}

doInBackground() 方法中调用SwingUtilities.invokeAndWait() 是否有效?我对此进行了一些线程分析,结果如下:

一旦按下“开始”按钮,SwingWorker-pool-1-thread-1 线程就会变为绿色。 THEN,当满足if条件时,抛出错误,并显示错误对话框,线程变为yellowAWT-EventQueue-0线程上确实有一个绿色的“blip”,表示调用了 EDT。我等了大约 10 秒钟,按下“确定”,SwingWorker 线程又变绿了。

做这样的事情有什么潜在的陷阱吗?有没有人有通过SwingWorker 实时通知用户计算错误的经验?

说实话,这种方法让我很怀疑。它似乎不正统,但我不能肯定这是否是一个坏主意。

【问题讨论】:

  • 如果这是一个已处理的异常,您可以在 doInBackground 中返回 errorCode description.. 或当异常发生时调用 publish 以获取 process 而不是返回 Void调用并处理异常,或者您可以使用firePropertyChange 发生错误
  • 当然我可以返回 Void 以外的其他内容,但返回 Void 的是我的 SSCCE。我的实际应用程序可能需要返回中间结果。
  • SwingWorker 没有正确使用 doInBackground(workers 线程,不是 invokeAndWait 的地方,只有在 Initial Tread 之后不是 EDT,如果 EDT 处于活动状态,则会导致异常),使用 publish(在 EDT 上完成)对于 JOptionPane,
  • 你真正想做什么或知道什么
  • @mKorbel,根据this answer,这是invokeAndWait 的有效用法,因为 1) 它不是从 EDT 调用的,2) 我需要更新 GUI,3) 我需要我的线程要等到用户点击“确定”后再继续。 publish()process() 是不可能的。

标签: java swing swingworker event-dispatch-thread invokeandwait


【解决方案1】:

当用户实际需要批准时,我认为使用invokeAndWait() 没有问题。如果没有,如example 所示,SwingWorker&lt;Void, String&gt; 可以简单地调用publish(),数据和错误消息交错。附加在done() 中的适当消息将允许用户在必要时查看累积的输出。

【讨论】:

    猜你喜欢
    • 2013-11-27
    • 1970-01-01
    • 2016-08-18
    • 1970-01-01
    • 2012-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-29
    相关资源
    最近更新 更多