我有一个应用程序,该应用程序在启动时会从API中提取数据,并将其显示在JButtons的网格中。我已经根据API响应成功显示并生成了JButton,但是我的问题是每个Button都需要有一个图标,该图标也要从API直接拉到JButton图标中。
实现这一点很好,但我的问题是,由于该应用程序已同步逐个拉动每个图像图标,因此启动该应用程序大约需要10分钟。 附言我使用OkHttp作为我的http客户端。
有人可以帮我找到一种方法,也许可以加载按钮,然后在完全从API中拉出图像时逐渐加载图像。
我该怎么做? 如何异步执行此操作?
我尝试到处寻找,但无法将找到的答案成功应用于我的问题。
这是此问题的代码段。
提前谢谢!
static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();
// api post method
String post(String url, String json) throws IOException {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
return response.body().string();
}
}
// api call
try {
String json = "";
String response = post("http://myapi.com", json);
JSONObject JsonResponse = new JSONObject(response);
JSONArray devices = JsonResponse.getJSONArray("response");
int rows = (devices.length() / 4) + 3;
resultsPanel.setLayout(new GridLayout(rows, 0, 20, 20));
for(int d = 0; d < devices.length(); d++){
// store device details
JSONObject selectedDevice = devices.getJSONObject(d);
// create button
JButton device = new JButton();
// style button
Border lineBorder = new LineBorder(new java.awt.Color(238, 238, 238));
Border padding = new EmptyBorder(0, 10, 0, 0);
device.setIcon(new javax.swing.ImageIcon(getClass().getResource("/assets/shield_32.png")));
device.setIconTextGap(20);
device.setText(devices.getJSONObject(d).get("name").toString());
device.setPreferredSize(new Dimension(100, 100));
device.setBackground(new java.awt.Color(255, 255, 255));
device.setFont(new java.awt.Font("Arial", 0, 12));
device.setVerticalTextPosition(SwingConstants.BOTTOM);
device.setHorizontalTextPosition(SwingConstants.CENTER);
device.setBorder(new CompoundBorder(lineBorder, padding));
device.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
device.setFocusable(false);
// event handling
device.addActionListener((java.awt.event.ActionEvent evt) -> {
System.out.println("Selected: " + ((JButton) evt.getSource()).getText());
deviceNameLbl.setText(((JButton) evt.getSource()).getText());
deviceImgLbl.setIcon(new javax.swing.ImageIcon(getClass().getResource("/assets/shield_350.png")));
getDevicePattern(selectedDevice.get("deviceModelID").toString());
CardLayout card = (CardLayout)mainPanel.getLayout();
card.show(mainPanel, "material_design");
});
// add button to panel
resultsPanel.add(device);
}
} catch (IOException ex) {
Logger.getLogger(ISoD.class.getName()).log(Level.SEVERE, null, ex);
}
答案 0 :(得分:0)
我终于设法解决了这个问题。
当从API中提取图像图标时,我使用了SwingWorker类来异步设置图像图标。这是我一直在寻找的完美效果!
这是完整的解决方案:
主类(JFrame)
static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();
String post(String url, String json) throws IOException {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
return response.body().string();
}
}
try {
String json = "";
String response = post("http://my-api.com/images", json);
JSONObject JsonResponse = new JSONObject(response);
JSONArray devices = JsonResponse.getJSONArray("response");
int rows = (devices.length() / 4) + 3;
resultsPanel.setLayout(new GridLayout(rows, 0, 20, 20));
for(int d = 0; d < devices.length(); d++){
// store device details
JSONObject selectedDevice = devices.getJSONObject(d);
// create button
JButton device = new JButton();
// extracting icon url from api response
URL imageURL = new URL(devices.getJSONObject(d).get("brandImage").toString());
// style button
Border lineBorder = new LineBorder(new java.awt.Color(238, 238, 238));
Border padding = new EmptyBorder(0, 10, 0, 0);
device.setIcon(new javax.swing.ImageIcon(getClass().getResource("/assets/stock_image.png")));
device.setIconTextGap(20);
device.setText(devices.getJSONObject(d).get("name").toString());
device.setPreferredSize(new Dimension(100, 100));
device.setBackground(new java.awt.Color(255, 255, 255));
device.setFont(new java.awt.Font("Arial", 0, 12));
device.setVerticalTextPosition(SwingConstants.BOTTOM);
device.setHorizontalTextPosition(SwingConstants.CENTER);
device.setBorder(new CompoundBorder(lineBorder, padding));
device.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
device.setFocusable(false);
// add button to panel
resultsPanel.add(device);
// asynchronously load images from api response
new ImageWorker(imageURL, device).execute();
}
} catch (IOException ex) {
Logger.getLogger(ISoD.class.getName()).log(Level.SEVERE, null, ex);
}
SwingWorker类
public class ImageWorker extends SwingWorker<ImageIcon, Void>{
URL imageURL;
ImageIcon brandImage;
JButton device;
public ImageWorker(URL imageURL, JButton device){
this.imageURL = imageURL;
this.device = device;
}
@Override
protected ImageIcon doInBackground() throws Exception {
brandImage = new ImageIcon(imageURL);
Image rawBrandImage = brandImage.getImage();
Image newimg = rawBrandImage.getScaledInstance(32, 32, java.awt.Image.SCALE_SMOOTH);
brandImage = new ImageIcon(newimg);
return brandImage;
}
@Override
protected void done() {
// leave as default zagg shield icon if no brand icon is returned by api
if (brandImage.getIconWidth() == 32 && brandImage.getIconHeight() == 32) {
device.setIcon(brandImage);
}
}
}