Обработка ошибок в SwingWorker
Мой вопрос основывается на теории, но удовлетворяет конкретную потребность, которая у меня есть.
Что вы делаете, когда ваш SwingWorker генерирует исключение, которое вы а) можете ожидать и б) необходимо восстановить и продолжить, но вы хотите уведомить пользователя о том, что произошла эта ошибка? Как вы получаете ожидаемое исключение и уведомляете пользователя, не нарушая "Нет кода Swing от 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();
}
}
}
Это действительно, чтобы позвонить SwingUtilities.invokeAndWait()
в пределах doInBackground()
метод? Я сделал некоторые профилирование потоков по этому вопросу, и результаты были такими:
После нажатия кнопки "Перейти" SwingWorker-pool-1-thread-1
нить идет зеленая. ТОГДА, когда условие if выполнено, выдается ошибка, и отображается диалоговое окно с сообщением об ошибке, нить становится желтой, и на AWT-EventQueue-0
поток, указывающий, что EDT был вызван. Я подождал около 10 секунд, нажал "ОК", и SwingWorker
нить снова стала зеленой.
Есть ли потенциальные подводные камни, чтобы сделать что-то подобное? Кто-нибудь имеет опыт уведомления пользователей об ошибках вычислений в режиме реального времени от SwingWorker
?
Я буду честен, такой подход вызывает у меня подозрение. Это кажется неортодоксальным, но я не могу с уверенностью сказать, является ли это плохой идеей.
1 ответ
Я не вижу проблем с использованием invokeAndWait()
когда пользователь действительно должен одобрить. Если нет, как показано в этом примере, SwingWorker<Void, String>
можно просто позвонить publish()
с чередованием данных и сообщений об ошибках. Подходящее сообщение добавлено в done()
позволит пользователю просматривать накопленный результат при необходимости.