2013-12-13 22 views
5

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:

enter image description here

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.

+0

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

+0

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

+0

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

risposta

4

Non vedo alcun problema con l'utilizzo di invokeAndWait() quando l'utente in realtà ha bisogno di da approvare. In caso contrario, come mostrato in questo example, un SwingWorker<Void, String> può semplicemente chiamare publish() con dati e messaggi di errore intercalati. Un messaggio appropriato aggiunto in done() consentirebbe all'utente di rivedere l'output accumulato se necessario.