我有许多图像通过一系列线程HTTP网络调用获取。我正在使用Callables和Futures来管理这个过程。当每个图像从服务器返回时,我想在JPanel上显示它而不等待其他图像返回。
此代码有效,但在所有图像都返回之前,UI不会更新:
private void loadAndDisplayImages() throws InterruptedException, ExecutionException {
final List<Callable<Image>> partitions = new ArrayList<Callable<Image>>();
for(final MediaFeedData data : imagesList) {
partitions.add(new Callable<Image>() {
public Image call() throws Exception {
String url = data.getImageUrl();
return ImageDisplayer.displayImageFromUrl(url, imageSize);
}
}
});
}
// for testing, use only a single thread to slow down rendering
final ExecutorService executorPool = Executors.newFixedThreadPool(1); //numImages);
// run each callable, capture the results in a list of futures
final List<Future<Image>> futureImages =
executorPool.invokeAll(partitions, 10000, TimeUnit.SECONDS);
for(final Future<Image> img : futureImages) {
Image image = img.get(); // this will block the UI
final ImageButton imageButton = new ImageButton(image, imageSize);
SwingUtilities.invokeLater(new Runnable(){
@Override public void run() {
imagesPanel.add(imageButton);
frame.validate();
frame.setVisible(true);
}
});
}
executorPool.shutdown();
}
答案 0 :(得分:2)
考虑将SwingWorker
与ExecutorService
...
public class ImageLoaderWorker extends SwingWorker<Image, Image> {
private File source;
private JPanel container;
public ImageLoaderWorker(File source, JPanel container) {
this.source = source;
this.container = container;
}
@Override
protected Image doInBackground() throws Exception {
return ImageIO.read(source);
}
@Override
protected void done() {
try {
Image img = get();
JLabel label = new JLabel(new ImageIcon(img));
container.add(label);
container.revalidate();
container.repaint();
} catch (InterruptedException | ExecutionException ex) {
ex.printStackTrace();
}
}
}
ExecutorService executor = Executors.newFixedThreadPool(4);
File images[] = new File("...").listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
String name = pathname.getName().toLowerCase();
return name.endsWith(".jpg") || name.endsWith(".png");
}
});
for (File img : images) {
executor.submit(new ImageLoaderWorker(img, this));
}
这只是扫描目录并加载图像,但概念基本相同......
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileFilter;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.Scrollable;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestImageLoader {
public static void main(String[] args) {
new TestImageLoader();
}
public TestImageLoader() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(new TestPane()));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel implements Scrollable {
public TestPane() {
setLayout(new GridLayout(0, 4));
ExecutorService executor = Executors.newFixedThreadPool(4);
File images[] = new File("...").listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
String name = pathname.getName().toLowerCase();
return name.endsWith(".jpg") || name.endsWith(".png");
}
});
for (File img : images) {
executor.submit(new ImageLoaderWorker(img, this));
}
}
@Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(600, 600);
}
@Override
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
return 128;
}
@Override
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
return 128;
}
@Override
public boolean getScrollableTracksViewportWidth() {
return false;
}
@Override
public boolean getScrollableTracksViewportHeight() {
return false;
}
}
public class ImageLoaderWorker extends SwingWorker<Image, Image> {
private File source;
private JPanel container;
public ImageLoaderWorker(File source, JPanel container) {
this.source = source;
this.container = container;
}
@Override
protected Image doInBackground() throws Exception {
return ImageIO.read(source);
}
@Override
protected void done() {
try {
Image img = get();
JLabel label = new JLabel(new ImageIcon(img));
container.add(label);
container.revalidate();
container.repaint();
} catch (InterruptedException | ExecutionException ex) {
ex.printStackTrace();
}
}
}
}