【问题标题】:Why isn't my image downloading when I use a SwingWorker but downloads when I don't?为什么我使用 SwingWorker 时无法下载我的图像,但不使用时却下载了?
【发布时间】:2017-07-21 02:25:26
【问题描述】:

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

使用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);
    }
}

独立Downloader类的图片下载(注意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);
        }
    }
}

【问题讨论】:

  • 等等。您之前不是问过是否应该始终在工作对象上调用 get() 吗?我们不是告诉过你“是的,你应该总是这样做来捕获抛出的异常”?
  • 我实际上不必使用 get(),它只是帮助捕获异常以解决问题。作为java新手,我从你的解释中不明白这一点,但我从这个答案中明白了。感谢您的帮助!

标签: java debugging download swingworker


【解决方案1】:

您应该在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()的返回值,它实际上是一个字节的数据,而不是读取的字节数。这对 I/O 没有明显影响,但会破坏percentCompleted 的值。这最终将大于 100 的值传递给setProgress,这会引发异常。该行应改为totalBytesRead++;

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

【讨论】:

  • 感谢您清晰详细的解释!它帮助很大。
猜你喜欢
  • 1970-01-01
  • 2021-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-07
  • 2020-08-27
相关资源
最近更新 更多