2017-07-21 3 views
0

Je crée une barre de progression pour surveiller un téléchargement d'image. Le téléchargement d'image ne fonctionne pas - il génère un fichier mesurant 0 octet. Si je déplace mon code vers une classe autonome sans SwingWorker, le téléchargement d'image fonctionne. J'ai joué avec cela pendant un moment et je ne sais toujours pas ce que je fais mal. Les deux blocs de code sont identiques. Tous les conseils seraient très appréciés!Pourquoi mon image n'est-elle pas téléchargée lorsque j'utilise un SwingWorker mais que je télécharge quand je ne l'utilise pas?

image télécharger avec SwingWorker (prendre note doInBackground):

package download_progress_bar; 

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 
import java.beans.*; 
import java.net.*; 
import java.io.*; 

public class ProgressBar implements ActionListener, PropertyChangeListener { 
    private JFrame frame; 
    private JPanel gui; 
    private JButton button; 
    private JProgressBar progressBar; 
    private SwingWorker<Void, Void> worker; 
    private boolean done; 

    public ProgressBar() { 
     done = false; 
     customizeFrame(); 
     createMainPanel(); 
     createProgressBar(); 
     createButton(); 
     addComponentsToFrame(); 
    } 

    private void customizeFrame() { 
     frame = new JFrame(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    } 

    private void createMainPanel() { 
     gui = new JPanel(); 
     gui.setLayout(new BorderLayout()); 
    } 

    private void createProgressBar() { 
     progressBar = new JProgressBar(0, 100); 
     progressBar.setStringPainted(true); // renders a progress string 
    } 

    private void createButton() { 
     button = new JButton("Start download"); 
     button.addActionListener(this); 
    } 

    /** 
    * Invoked when user clicks the button. 
    */ 
    public void actionPerformed(ActionEvent evt) { 
     button.setEnabled(false); 
     // NOTE: Instances of javax.swing.SwingWorker are not reusable, 
     // so we create new instances as needed 
     worker = new Worker(); 
     worker.addPropertyChangeListener(this); 
     worker.execute(); 
    } 

    class Worker extends SwingWorker<Void, Void> { 
     /* 
     * Main task. Executed in worker thread. 
     */ 
     @Override 
     protected Void doInBackground() throws MalformedURLException { 
      // Create a URL object for a given URL 
      String src = "https://lh3.googleusercontent.com/l6JAkhvfxbP61_FWN92j4ulDMXJNH3HT1DR6xrE7MtwW-2AxpZl_WLnBzTpWhCuYkbHihgBQ=s640-h400-e365"; 
      URL url = new URL(src); 
      // Open connection on the URL object 

      try { 
       HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 

       // Always check response code first 
       int responseCode = connection.getResponseCode(); 
       if (responseCode == HttpURLConnection.HTTP_OK) { 
        System.out.println(responseCode); 

        // Open input stream from connection 
        BufferedInputStream in = new BufferedInputStream(connection.getInputStream()); 
        // Open output stream for file writing 
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("cat.jpg")); 

        int bytesRead = - 1; 
        int totalBytesRead = 0; 
        int percentCompleted = 0; 

        while ((bytesRead = in.read()) != -1) { 
         out.write(bytesRead); 
         totalBytesRead += bytesRead; 
         percentCompleted = totalBytesRead * 100/connection.getContentLength(); 

         System.out.println("..." + percentCompleted); 
         this.setProgress(percentCompleted); 
        } 

        // Close streams 
        out.close(); 
        in.close(); 
       } 
      } catch (IOException ex) { 
       System.out.println(ex); 
       this.setProgress(0); 
       cancel(true); 
      } 

      return null; 
     } 

     /* 
     * Executed in event dispatching thread 
     */ 
     @Override 
     protected void done() { 
      button.setEnabled(true); 
      if (!isCancelled()) { 
       System.out.println("File has been downloaded successfully!"); 
      } else { 
       System.out.println("There was an error in downloading the file."); 
      } 
     } 
    } 

    /** 
    * Invoked when task's progress property changes. 
    */ 
    public void propertyChange(PropertyChangeEvent evt) { 
     System.out.println(evt); 
     // NOTE: By default two property states exist: "state" and "progress" 
     if (evt.getPropertyName().equals("progress")) { 
      int progress = (Integer) evt.getNewValue(); 
      progressBar.setValue(progress); 
      System.out.println(String.format(
        "Completed %d%% of task.\n", progress)); 
     } 
    } 

    private void addComponentsToFrame() { 
     gui.add(progressBar, BorderLayout.CENTER); 
     gui.add(button, BorderLayout.SOUTH); 
     frame.add(gui); 
     frame.pack(); 
    } 

    public void activate() { 
     frame.setVisible(true); 
    } 
} 

télécharger Image avec classe autonome Downloader (prendre note download):

package download_progress_bar; 

import java.net.*; 
import java.io.*; 

public class Downloader { 
    public static void main(String[] args) throws IOException { 
     download(); 
    } 

    public static void download() throws IOException { 
     // Create a URL object for a given URL 
     String src = "https://lh3.googleusercontent.com/l6JAkhvfxbP61_FWN92j4ulDMXJNH3HT1DR6xrE7MtwW-2AxpZl_WLnBzTpWhCuYkbHihgBQ=s640-h400-e365"; 
     URL url = new URL(src); 
     // Open connection on the URL object 

     try { 
      HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 

      // Always check response code first 
      int responseCode = connection.getResponseCode(); 
      if (responseCode == HttpURLConnection.HTTP_OK) { 
       System.out.println(responseCode); 

       // Open input stream from connection 
       BufferedInputStream in = new BufferedInputStream(connection.getInputStream()); 
       // Open output stream for file writing 
       BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("test.jpg")); 

       int bytesRead = - 1; 
       int totalBytesRead = 0; 
       int percentCompleted = 0; 

       while ((bytesRead = in.read()) != -1) { 
        out.write(bytesRead); 
        totalBytesRead += bytesRead; 
        percentCompleted = totalBytesRead * 100/connection.getContentLength(); 

        System.out.println("..." + percentCompleted); 
       } 

       // Close streams 
       out.close(); 
       in.close(); 
      } 
     } catch (IOException ex) { 
      System.out.println(ex); 
     } 
    } 
} 
+0

Attendre. N'avez-vous pas déjà demandé précédemment si 'get()' devrait toujours être appelé sur l'objet worker? Et ne vous avons-nous pas dit "oui, vous devriez comme vous devriez toujours le faire pour piéger les exceptions jetées"? –

+0

Je n'avais pas vraiment besoin d'utiliser get(), cela aide simplement à détecter les exceptions pour résoudre le problème. Étant nouveau à Java, je n'ai pas compris cela à partir de votre explication, mais je l'ai fait à partir de cette réponse. Merci de votre aide! – briennakh

Répondre

2

Vous devez appeler get() dans done(). Si doInBackground déclenche une exception, alors get() lira un ExecutionException dont la cause est l'exception de doInBackground.

Quelque chose comme ceci:

@Override 
protected void done() { 
    button.setEnabled(true); 
    try { 
     if (!isCancelled()) { 
      get(); 
      System.out.println("File has been downloaded successfully!"); 
      return; 
     } 
    } catch (InterruptedException x) { 
     x.printStackTrace(); 
    } catch (ExecutionException x) { 
     // This should print an IllegalArgumentException 
     // if me theory (explained below) is correct. 
     x.getCause().printStackTrace(); 
    } 
    System.out.println("There was an error in downloading the file."); 
} 

Ma théorie est que le problème est lié à cette ligne:

totalBytesRead += bytesRead; 

Depuis bytesRead est la valeur de retour de InputStream.read(), il est en fait un octet de données, pas le nombre d'octets lus. Cela n'a pas d'effet évident sur les E/S, mais cela corrompt la valeur de percentCompleted. Cela finit par passer une valeur qui est supérieure à 100 à setProgress qui déclenche une exception. La ligne devrait être totalBytesRead++; à la place.

Vous pouvez vérifier ma théorie avec la modification susmentionnée au done().

+0

Merci pour l'explication claire et détaillée! Ça a beaucoup aidé. – briennakh