为什么当我使用 SwingWorker 时我的图像不下载,而当我不使用时下载?

Why isn't my image downloading when I use a SwingWorker but downloads when I don't?

我正在创建一个进度条来监控图像下载。图片下载不起作用——它生成一个大小为 0 字节的文件。如果我将我的代码移动到没有 SwingWorker 的独立 class,则图像下载有效。我已经玩了一段时间了,但我仍然不知道自己做错了什么。这两个代码块是相同的。任何提示将不胜感激!

SwingWorker下载图片(注意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);
    }
}

单机下载图片Downloaderclass(注意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);
        }
    }
}

您应该在 done() 中调用 get()。如果 doInBackground 抛出异常,那么 get() 将抛出 ExecutionException 其原因是来自 doInBackground.

的异常

像这样:

@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.");
}

我的理论是这个问题与这一行有关:

totalBytesRead += bytesRead;

因为 bytesReadInputStream.read(), it's actually a byte of data, not the number of bytes read. This doesn't have an obvious effect on the I/O, but it corrupts the value of percentCompleted. This ends up passing a value which is greater than 100 to setProgress 的 return 值,它会引发异常。该行应该改为 totalBytesRead++;

你可以通过上述对done()的修改来验证我的理论。