是否可以等待一個方法(比如 METHOD1)完成,但如果它運行的時間超過 X 秒,呼叫另一個方法直到 METHOD1 回傳?
一些偽代碼:
method1();
startCountdown(1000); // time in millis
while (method1() still running) {
method2(); // shows a popup with spinner (Swing/AWT)
}
我想,它必須是用并發來完成的,但我不習慣并發編程。所以我不知道如何開始......
使用的 UI 框架是 Swing/AWT。
uj5u.com熱心網友回復:
因此,基本思想是使用 aSwingWorker和 Swing的組合Timer。
我們的想法是,如果Timer觸發前的SwingWorker是DONE,你執行一些其他作業流,否則你停Timer,例如...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import javax.swing.Timer;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JLabel label;
private JButton startButton;
boolean hasCompleted = false;
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
label = new JLabel("Waiting for you");
startButton = new JButton("Start");
add(label, gbc);
add(startButton, gbc);
startButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
startButton.setEnabled(false);
startWork();
}
});
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
protected void startWork() {
label.setText("Something wicked this way comes");
// You could build an isoloated workflow, which allowed you to pass
// three targets, the thing to be executed, the thing to be
// executed if time run over and the thing to be executed when
// the task completed (all via a single interface),
// but, you get the idea
Timer timer = new Timer(2000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (hasCompleted) {
return;
}
label.setText("Wickedness is a bit slow today");
}
});
timer.setRepeats(false);
SomeLongRunningOperation worker = new SomeLongRunningOperation();
worker.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
switch (worker.getState()) {
case DONE:
hasCompleted = true;
timer.stop();
label.setText("All is done");
startButton.setEnabled(true);
break;
}
}
});
worker.execute();
timer.start();
}
}
public class SomeLongRunningOperation extends SwingWorker<Void, Void> {
@Override
protected Void doInBackground() throws Exception {
Thread.sleep(5000);
return null;
}
}
}
玩轉時間,看看你得到什么不同的效果。
為什么使用SwingWorker? 因為它有自己的狀態回呼,所以更容易處理
正如我在評論中所說,您可以將作業流程提煉成一個可重用的概念,例如......
public class TimedTask<V> {
public static interface Task<V> {
public V execute() throws Exception;
}
public static interface TimedTaskListener<V> extends EventListener {
public void taskIsTakingLongThenExepected(TimedTask task);
public void taskDidComplete(TimedTask task, V value);
}
private Task<V> task;
private TimedTaskListener<V> listener;
private V value;
private int timeOut;
private Timer timer;
private SwingWorker<V, Void> worker;
private boolean hasCompleted = false;
public TimedTask(int timeOut, Task<V> task, TimedTaskListener<V> listener) {
this.task = task;
this.listener = listener;
this.timeOut = timeOut;
}
public V getValue() {
return value;
}
public int getTimeOut() {
return timeOut;
}
protected Task<V> getTask() {
return task;
}
protected TimedTaskListener<V> getListener() {
return listener;
}
public void execute() {
if (timer != null || worker != null) {
return;
}
hasCompleted = false;
worker = new SwingWorker<V, Void>() {
@Override
protected V doInBackground() throws Exception {
value = task.execute();
return value;
}
};
worker.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
switch (worker.getState()) {
case DONE:
hasCompleted = true;
timer.stop();
getListener().taskDidComplete(TimedTask.this, value);
break;
}
}
});
timer = new Timer(getTimeOut(), new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (hasCompleted) {
return;
}
getListener().taskIsTakingLongThenExepected(TimedTask.this);
}
});
timer.setRepeats(false);
worker.execute();
timer.start();
}
}
然后你可以startWork用類似的東西替換第一個例子中的方法......
protected void startWork() {
label.setText("Something wicked this way comes");
TimedTask.Task<Void> task = new TimedTask.Task<Void>() {
@Override
public Void execute() throws Exception {
Thread.sleep(5000);
return null;
}
};
TimedTask<Void> timedTask = new TimedTask(2000, task, new TimedTask.TimedTaskListener<Void>() {
@Override
public void taskIsTakingLongThenExepected(TimedTask task) {
label.setText("Wickedness is taking it's sweet time");
}
@Override
public void taskDidComplete(TimedTask task, Void value) {
label.setText("Wickedness has arrived");
startButton.setEnabled(true);
}
});
timedTask.execute();
}
uj5u.com熱心網友回復:
雖然SwingWorker是適合這項作業的工具,但對于簡單的任務,您可以使用Threadoff-edt 長時間任務和搖擺Timer來更新 GUI:
import java.awt.*;
import javax.swing.*;
import javax.swing.Timer;
public class Main{
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.add(new TestPane());
frame.pack();
frame.setVisible(true);
}
}
class TestPane extends JPanel{
private static Dimension size = new Dimension(250, 100);
private final JLabel label;
private final JButton start;
private int counter;
private Timer timer;
public TestPane() {
setLayout(new BorderLayout(10, 10));
label = new JLabel("Click START to run long process", JLabel.CENTER);
add(label,BorderLayout.NORTH);
start = new JButton("START");
start.addActionListener(e-> start() );
add(start, BorderLayout.SOUTH);
}
private void start() {
start.setEnabled(false);
int processRunTime = 10;
int updateTime = 1; //if this value >= processRunTime update() is not invoked
counter = 1;
simulateLongProcessOf(processRunTime);
timer = new Timer(1000*updateTime, e->update(counter ));
label.setText("Long process started");
timer.start();
}
private void stop() {
label.setText("Long process ended");
timer.stop();
start.setEnabled(true);
}
@Override
public Dimension preferredSize() {
return size;
}
private void simulateLongProcessOf(int seconds){
Thread t1 = new Thread(()->{
try {
Thread.sleep(1000*seconds);
} catch (InterruptedException ex) {
ex.printStackTrace();
}finally {
SwingUtilities.invokeLater(()->stop());
}
});
t1.start();
}
private void update(int count){
label.setText("Update # " count " : long process is running" );
}
}
uj5u.com熱心網友回復:
我以前一直在努力解決這個問題。我最終做的是創建一個單獨的類來擴展 AsyncTask。向回傳我的物件??的此類添加了一個介面/偵聽器。就在我開始我的 AsyncTask 之前,我將禁用按鈕并設定一個加載微調器。一旦 AsyncTask 回傳,我將進行處理并重新啟用按鈕并取下加載微調器。粗略地說,我在示例中進行了休息呼叫,但它可以應用于任何需要一段時間的事情。這是一個比 while 回圈更好的選擇的原因是它不會燃燒回圈檢查條件。
public class RestCall extends AsyncTask {
private Context mContext;
private static final String TAG = "RestCall";
private AsyncResponse mListener;
public RestCall(Context context, URL url, AsyncResponse listener) {
this.mListener = listener;
this.mContext = context;
this.url = url;
}
public interface AsyncResponse {
void processFinish(JSONArray results);
}
@Override
protected Object doInBackground(Object[] objects) {
Log.d(TAG, "doInBackground: Thread: " Thread.currentThread().getName());
return getResultsInJSONArray(url);
}
private JSONArray getResultsInJSONArray(URL url) {
//Here is where you will be doing the bulk of the work
//Doing a rest call and
//Processing results to JSONArray
}
@Override
protected void onPostExecute(Object o) {
super.onPostExecute(o);
Log.d(TAG, "onPostExecute: Handing off Object");
mListener.processFinish((JSONArray) o);
}
現在,在您原來的班級中,您將在班級中添加以下內容:
public class myClass
private restCall call;
比從您制作的那個界面創建一個監聽器。然后將結果傳遞給一個方法。
restCall.AsyncResponse listener = results -> handleResults(results);
通過偵聽器設定,您可以執行 AsyncTask。
//here is were you would throw up the loading bar.
call = new restCall(this, url, listener);
call.execute();
private void handleResults(JSONArray results){
//process what you need to
//take down loading bar
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/363041.html
上一篇:使用ImageIcon添加影像時發生“執行緒“AWT-EventQueue-0”java.lang.NullPointerException中的例外
