java - JavaFX 任务/线程没有一致地填充表格视图
问题描述
所以,我需要使用 JavaFX 线程填充表格视图,但表格只填充了大约 70% 的时间。我正在查看我的代码,但我真的找不到问题出在哪里,我的猜测是在从 db 成功检索/处理数据之前,该任务正在以某种方式执行。谢谢是提前:)
private Executor exec;
private ObservableList<User> cellData = FXCollections.observableArrayList();
.
.
.
public void fillTable(HashMap<String,Object> whereClause){
Task<List<User>> task = new Task<List<User>>(){
@Override
public ObservableList<User> call(){
cellData.clear();
cellData.addAll(userRepository.getAll(whereClause));
userId.setCellValueFactory(new PropertyValueFactory<>("userID"));
userName.setCellValueFactory(new PropertyValueFactory<>("userName"));
userMail.setCellValueFactory(new PropertyValueFactory<>("userMail"));
userPhone.setCellValueFactory(new PropertyValueFactory<>("userPhone"));
isAdmin.setCellValueFactory(cellData -> {
String isAdminAsString = cellData.getValue().isAdmin() ? "Admin" : "Medic";
return new ReadOnlyStringWrapper(isAdminAsString);
});
isDeleted.setCellValueFactory(cellData -> {
String isActiveUser = cellData.getValue().isDeleted() ? "No" : "Yes";
return new ReadOnlyStringWrapper(isActiveUser);
});
logger.info("Cell values set");
return cellData;
}
};
exec.execute(task);
task.setOnFailed(e -> System.out.println(task.getException().getMessage()));
task.setOnSucceeded(e -> userTable.setItems((ObservableList<User>) task.getValue()));
logger.info("Fill user Table Task executed");
解决方案
您没有为正确、完全自信的答案提供足够的上下文,但我猜您遇到了与线程相关的问题。JavaFX 不是线程安全的;使用错误的线程更新 UI 可能会导致未定义的行为,例如数据仅出现约 70% 的时间。JavaFX 中有一条重要的规则,您必须始终遵循:
- 切勿读取或写入直接或间接连接到除JavaFX 应用程序线程之外的线程上的实时场景图的对象的状态。
您的代码不遵循此规则。在您的call
方法中,您正在对各种sTask
进行结构修改cellData
和设置。这导致所述对象被正在执行的任何线程修改。如果有任何提示,则该线程绝对不是JavaFX Application Thread。cellValueFactory
TableColumn
Task
Executor
我不确定你为什么首先在方法中设置cellValueFactory
你TableColumn
的 s call
。单元格值工厂是只需要完成一次的配置——在您创建时TableColumn
(或之后不久)。换句话说,在call
方法中配置单元格值工厂是错误的,不仅因为它发生在后台线程上,还因为每次执行Task
. 从方法中删除 set-the-cell-value-factory 代码,call
并在需要时将其移动到创建TableColumn
s 的位置。如果您使用 FXML,并且TableColumn
为您创建并注入了 s,那么控制器的initialize
方法是进行此类配置的好地方。
您的cellData
列表与TableView
您的Task
. 在后台线程上进行修改cellData
将通知TableView
同一线程上的这些更改(在进行更改的同一线程上调用侦听器)。简单的解决方案是让您的Task
退货成为新 List
的,然后更新TableView
如果成功。
Task<List<User>> task = new Task<List<User>>() {
@Override protected List<User> call() throws Exception {
return userRepository.getAll(whereClause);
}
});
task.setOnSucceeded(event -> userTable.getItems().setAll(task.getValue()));
task.setOnFailed(event -> task.getException().printStackTrace());
exec.execute(task);
的setAll
方法ObservableList
将首先清除列表,然后添加给定集合(或数组)的所有元素。这比调用clear
其次更有效,addAll
因为它只导致一个更改事件。此外,如果您想继续使用cellData
,假设您之前已将其设置为表格的项目;只是使用cellData.setAll(task.getValue())
。
关于使用:
task.setOnSucceeded(e -> userTable.setItems((ObservableList<User>) task.getValue()));
由于您显然希望 aObservableList<User>
被返回,因此您应该使用 aTask<ObservableList<User>>
而不是 a Task<List<User>>
。这将意味着getValue()
返回ObservableList<User>
,因此不需要演员表。但是,如果您遵循上述建议,那么这无关紧要。
推荐阅读
- reactjs - Typescript 中抽象泛型容器类的子类的装饰器
- apache-kafka - 无法使用 KSQL 创建流
- android - 为什么我的自定义 TextView 不继承字体?
- python - jupyter notebook:再次显示seaborn情节
- android - 在 setGridViewItemClickListener 中出现错误以及如何显示可绘制的图像
- slack-api - 用于获取和设置团队偏好的 API
- javascript - 在网格元素内垂直居中文本
- python - 请求避免 ddos 保护
- widget - Flutter - 动态小部件定位
- php - php yii 框架,更改 connect.php 文件中的主机会导致网站挂起?