JavaFX任务updateValue在FX应用程序线程上引发IllegalStateException:非
我有一个简单的应用程序,只有一个JavaFX窗口。我正在将数据发送到for循环中的Azure IoTHub。这个for循环位于JavaFX任务中,for循环有一个很小的延迟(Thread.sleep(300)),因此可以在UI上显示进度。我有两个标签,我想在数据传输过程中更新,始终显示最新发送的数据。我为此提供了以下帮助器类:JavaFX任务updateValue在FX应用程序线程上引发IllegalStateException:非,javafx,javafx-8,Javafx,Javafx 8,我有一个简单的应用程序,只有一个JavaFX窗口。我正在将数据发送到for循环中的Azure IoTHub。这个for循环位于JavaFX任务中,for循环有一个很小的延迟(Thread.sleep(300)),因此可以在UI上显示进度。我有两个标签,我想在数据传输过程中更新,始终显示最新发送的数据。我为此提供了以下帮助器类: public class DataHelper { private StringProperty date = new SimpleStringProperty()
public class DataHelper {
private StringProperty date = new SimpleStringProperty();
private StringProperty count = new SimpleStringProperty();
public DataHelper() {
}
public DataHelper(String date, String count) {
this.date.setValue(date);
this.count.setValue(count);
}
//getters and setters
}
下面是我的UI控制器类中的sendErrorsToHub方法:
private void sendErrorsToHub(List<TruckErrorForCloud> toCloud) {
DataHelper dataHelper = new DataHelper("", "");
Task task = new Task<DataHelper>() {
@Override
public DataHelper call() {
try {
int i = 0;
for (TruckErrorForCloud error : toCloud) {
Thread.sleep(300);
i++;
String strMessage = Utility.toPrettyJson(null, error);
if (strMessage != null) {
Message msg = new Message(strMessage);
msg.setMessageId(java.util.UUID.randomUUID().toString());
client.sendEventAsync(msg, null, null);
}
updateProgress(i, toCloud.size());
DataHelper dh = new DataHelper(error.getErrorTimeStamp().substring(0, error.getErrorTimeStamp().length() - 9),
String.valueOf(error.getCount()));
updateValue(dh);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void updateValue(DataHelper value) {
super.updateValue(value);
dataHelper.setDate(value.getDate());
dataHelper.setCount(value.getCount());
}
//succeeded method omitted
};
dateValue.textProperty().bind(dataHelper.dateProperty());
countValue.textProperty().bind(dataHelper.countProperty());
progressBar.progressProperty().bind(task.progressProperty());
new Thread(task).start();
}
(138是行Task Task=newtask(),155 updateValue(dh);,166 dataHelper.setDate(value.getDate());)
updateValue
不会自动在应用程序线程上运行,也不必在应用程序线程上运行它,因为它负责更新应用程序线程上任务的值属性
覆盖版本updateValue
中的代码在后台线程上执行需要在应用程序线程上运行的逻辑,不过:
dataHelper.setDate(value.getDate());
dataHelper.setCount(value.getCount());
绑定会导致从后台线程更新文本属性,因为上面的代码在后台线程上运行
在这种情况下,我建议使用不可变的DataHelper
类,并使用侦听器将ui更新为value
属性:
删除updateValue
覆盖和dataHelper
局部变量,用空字符串初始化gui,如有必要,将task
声明为task任务
,并执行以下操作以更新gui:
task.valueProperty().addListener((o, oldValue, newValue) -> {
if (newValue != null) {
dateValue.setText(newValue.getDate());
countValue.setText(newValue.getCount());
}
});
您也可以使用Platform.runLater
进行这些更新,因为这些更新发生的频率不足以导致使用Platform.runLater
过于频繁的问题。谢谢,这很有效。所以这个监听器在每次调用updateValue()时都会触发,对吗?不一定<代码>任务
使用原子引用
保留最新的值,但平台。用于更新的runLater
实际上在某个未指定的时间运行。这意味着您可能看不到属性的每个中间值。(请注意,call
的返回值也用于最后一次更新value
属性;这就是我添加null
检查的原因)
task.valueProperty().addListener((o, oldValue, newValue) -> {
if (newValue != null) {
dateValue.setText(newValue.getDate());
countValue.setText(newValue.getCount());
}
});