【发布时间】:2018-12-21 02:24:21
【问题描述】:
我的应用程序包含一个ListView,每次选择一个项目时都会启动一个后台任务。然后,后台任务在成功完成后更新 UI 上的信息。
但是,当用户快速单击一个又一个项目时,所有这些任务都会继续,最后完成的任务会“获胜”并更新 UI,而不管最后选择的是哪个项目。
我需要以某种方式确保此任务在任何给定时间仅运行一个实例,因此在启动新任务之前取消所有先前的任务。
这是一个演示该问题的 MCVE:
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class taskRace extends Application {
private final ListView<String> listView = new ListView<>();
private final Label label = new Label("Nothing selected");
private String labelValue;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
// Simple UI
VBox root = new VBox(5);
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(10));
root.getChildren().addAll(listView, label);
// Populate the ListView
listView.getItems().addAll(
"One", "Two", "Three", "Four", "Five"
);
// Add listener to the ListView to start the task whenever an item is selected
listView.getSelectionModel().selectedItemProperty().addListener((observableValue, oldValue, newValue) -> {
if (newValue != null) {
// Create the background task
Task task = new Task() {
@Override
protected Object call() throws Exception {
String selectedItem = listView.getSelectionModel().getSelectedItem();
// Do long-running task (takes random time)
long waitTime = (long)(Math.random() * 15000);
System.out.println("Waiting " + waitTime);
Thread.sleep(waitTime);
labelValue = "You have selected item: " + selectedItem ;
return null;
}
};
// Update the label when the task is completed
task.setOnSucceeded(event ->{
label.setText(labelValue);
});
new Thread(task).start();
}
});
stage.setScene(new Scene(root));
stage.show();
}
}
按随机顺序单击多个项目时,结果是不可预测的。我需要更新标签以显示上次执行的Task 的结果。
我是否需要以某种方式安排任务或将它们添加到服务中才能取消所有先前的任务?
编辑:
在我的真实应用程序中,用户从ListView 中选择一个项目,后台任务读取一个数据库(一个复杂的SELECT 语句)以获取与该项目相关的所有信息。然后这些详细信息会显示在应用程序中。
发生的问题是当用户选择一个项目但更改了他们的选择时,应用程序中显示的返回数据可能是第一个选择的项目,即使现在选择了一个完全不同的项目。
可以完全丢弃从第一个(即:不需要的)选择返回的任何数据。
【问题讨论】:
-
我能知道这个任务的真正用途吗?我的意思是该任务的业务规则是什么?然后当你说取消时,它的真正含义是什么?假设一个任务正在执行 REST 调用或执行存储过程……我们需要知道真正取消的任务是什么。
-
@NghiaDo - 查看我的编辑。谢谢。
-
那么,最终用户是否应该等到任务完成后再允许用户选择新项目?
-
不,我希望他们能够继续前进并随时选择新项目。
-
一个任务可能需要的最长时间是多少?