我正在创建一个进度条来监控图像下载。图像下载不起作用 - 它生成一个大小为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);
}
}
}
答案 0 :(得分:2)
您应该在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;
由于bytesRead
是InputStream.read()
的返回值,它实际上是一个数据字节,而不是读取的字节数。这对I / O没有明显影响,但它会破坏percentCompleted
的值。这最终会将大于100的值传递给setProgress
,从而引发异常。该行应为totalBytesRead++;
。
您可以通过前面对done()
的修改验证我的理论。