La mia domanda è una domanda basata su teoria, ma soddisfa un bisogno specifico che ho.Gestione degli errori in SwingWorker
Cosa si fa quando SwingWorker genera un'eccezione che a) può anticipare eb) devono essere ripristinati e continuano, ma si desidera avvisare l'utente che questo errore si è verificato? Come si afferra l'eccezione prevista e si avvisa l'utente senza violare la regola "No Swing code from doInBackground()
"?
Ho, in considerazione di questo problema, sviluppato un SSCCE che vorrei mettere avanti con le domande sottostanti.
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();
}
}
}
E 'valida per chiamare SwingUtilities.invokeAndWait()
all'interno del metodo doInBackground()
? Ho fatto qualche profiling Discussione su questo ei risultati sono stati in tal modo:
Una volta che il "Go" si preme il pulsante, il filo SwingWorker-pool-1-thread-1
va verde. ALLORA, quando viene soddisfatta la condizione if, viene generato l'errore e viene visualizzata la finestra di dialogo di errore, il thread diventa giallo e vi è effettivamente un "blip" verde sul thread AWT-EventQueue-0
, a indicare che l'EDT è stato richiamato. Ho aspettato circa 10 secondi, ho premuto "ok" e il thread SwingWorker
è diventato nuovamente verde.
Ci sono potenziali insidie nel fare qualcosa del genere? Qualcuno ha esperienza con la notifica agli utenti di errori di calcolo in tempo reale dal SwingWorker
?
Sarò onesto, questo approccio mi ha deluso. È sembra non ortodosso, ma non posso dire con certezza se questa è una cattiva idea.
Se è un'eccezione gestita, invece di restituire 'Void' in' doInBackground' restituisce un bean con 'errorCode'' description' .. o quando si verifica un'eccezione chiama 'publish' per ottenere' process' chiamato e gestire l'eccezione, oppure puoi usare 'firePropertyChange' che si verifica un errore – nachokk
Ben sicuro di poter restituire qualcosa di diverso da' Void' ma è il mio SSCCE che sta restituendo 'Void'. La mia vera applicazione potrebbe dover restituire risultati intermedi. – ryvantage
SwingWorker non è usato correttamente doInBackground (thread dei lavoratori, non posto per invokeAndWait, solo se non è EDT dopo il Tread iniziale, ha causato un'eccezione se EDT è attivo), usa publish (fatto su EDT) per JOptionPane, – mKorbel