并发任务更新复杂对象JavaFX-swingworker等价物?

并发任务更新复杂对象JavaFX-swingworker等价物?,javafx,concurrency,task,swingworker,Javafx,Concurrency,Task,Swingworker,我想在后台运行一个任务,更新视图中的中间结果。我正在尝试实现MVC JavaFX应用程序。任务在模型中定义。 我想发送到主threath部分结果,以便在视图中显示它们。 我使用updateValue()来实现这一点。此外,我在控制器中定义了对象属性和侦听器 我的问题是:每次在任务中执行updateValue()时,都不会触发侦听器中的方法changed()。为什么?我怎么能强迫它这么做 我没有发现太多复杂的例子 到目前为止,我所拥有的: Model.cpp ComplexObject _com

我想在后台运行一个任务,更新视图中的中间结果。我正在尝试实现MVC JavaFX应用程序。任务在模型中定义。 我想发送到主threath部分结果,以便在视图中显示它们。 我使用updateValue()来实现这一点。此外,我在控制器中定义了对象属性和侦听器

我的问题是:每次在任务中执行updateValue()时,都不会触发侦听器中的方法changed()。为什么?我怎么能强迫它这么做

我没有发现太多复杂的例子

到目前为止,我所拥有的:

Model.cpp

ComplexObject  _complexO;
public Task<ComplexObject> getModelTask() {
      return new Task<ComplexObject>() {
           @Override
           protected ComplexObject call() throws Exception {

            int    numberOfFiles = 0;
            boolean filesToRead = true;
            while (filesToRead){
                  // ....
              _complexO = new ComplexObject();
              try{
                   //..
                   if(f.exists()){
                       _complexO.initialize();
                       numberOfScans ++;

                     }
                    else{
                       _complexO.initializeToNull();
                     }

                  String stringNumber = Converter.toString(numberOfFiles);
                  updateMessage(stringNumber);                        
                  updateValue(_complexO );
              } catch(Exception ex){
                   ex.printStackTrace();
                   _complexO = null;
                   return _complexO;
              }
             filesToRead = areThereFilesToRead();
             }
             return _complexO;        
        }
   };
}
ComplexObject\u complexO;
公共任务getModelTask(){
返回新任务(){
@凌驾
受保护的ComplexObject调用()引发异常{
int numberOfFiles=0;
布尔文件存储=true;
while(文件存储){
// ....
_complexO=新的ComplexObject();
试一试{
//..
如果(f.exists()){
_complexO.initialize();
numberOfScans++;
}
否则{
_complexO.initializeToNull();
}
String stringNumber=Converter.toString(numberOfFiles);
更新消息(stringNumber);
updateValue(_complexO);
}捕获(例外情况除外){
例如printStackTrace();
_complexO=null;
返回_complexO;
}
filesToRead=areThereFilesToRead();
}
返回_complexO;
}
};
}
Controller.cpp

...

Task<  ComplexObject> task = _model.getModelTask();
_AJavaFXTextField.textProperty().bind(task.messageProperty());
_AJavaFXTextField.textProperty().addListener(new ChangeListener<String>() {

   @Override
   public void changed(ObservableValue observable, String oldValue, String newValue) {  
           System.out.println("Success with messageProperty!!" + newValue);
      }       
     });

SimpleObjectProperty<ComplexObject> complexObjectProperty = new SimpleObjectProperty<>();
complexObjectProperty.bind(task.valueProperty());
complexObjectProperty.addListener(new ChangeListener<ComplexObject>(){

   @Override
   public void changed(ObservableValue<? extends ComplexObject> observable, ComplexObject oldValue, ComplexObject newValue) {
      if(newValue.data == null ) {
        System.out.println("value is new!!! " + scansNumber);
      }
      else if(newValue.isValid()){
         System.out.println("I want to plot newValue data here");

       }
      }         
     });

   Thread th=  new Thread(task);
   System.out.println("call TASK");
   th.start();
}
。。。
TaskTask=\u model.getModelTask();
_AJavaFXTextField.textProperty().bind(task.messageProperty());
_AJavaFXTextField.textProperty().addListener(新的ChangeListener(){
@凌驾
公共无效已更改(ObservalEvalue observable、字符串oldValue、字符串newValue){
System.out.println(“messageProperty成功!!”+newValue);
}       
});
SimpleObjectProperty complexObjectProperty=新SimpleObjectProperty();
complexObjectProperty.bind(task.valueProperty());
complexObjectProperty.addListener(新的ChangeListener(){
@凌驾

public void changed(ObservableValue
任务
仅保证传递给
updateValue
的值或稍后传递的值将被设置为
value
属性。这样做是为了通过限制通知侦听器的更改数量来提高应用程序线程的性能

为什么为
messageProperty
触发绑定的次数比为
valueProperty
触发绑定的次数要多?触发次数应该相同

如上所述,根本无法保证更新的数量

为什么我发现在调试模式下,监听器的代码比正常执行时被触发的次数更多

在一般情况下,调试会使程序变小。
任务的线程更新频率越小,
任务
类更新属性之间的更新次数越少,跳过的更新次数也越少。(更新可能每帧或每几帧执行一次。)如果在任务中使用断点/步进器,当应用程序线程以正常速度运行时,可能会使
任务
非常慢


通过使用
列表
缓冲更新,您应该可以轻松地自行实现
发布

public abstract class JavaFXWorker<S, T> extends Task<S> {

    private List<T> chunks = new ArrayList<>();
    private final Object lock = new Object();
    private boolean chunkUpdating = false;

    protected final void publish(T... results) {
        synchronized (lock) {
            chunks.addAll(Arrays.asList(results));
            if (!chunkUpdating) {
                chunkUpdating = true;
                Platform.runLater(() -> {
                    List<T> cs;
                    synchronized (lock) {
                        cs = chunks;
                        // create new list to not unnecessary lock worker thread
                        chunks = new ArrayList<>();
                        chunkUpdating = false;
                    }
                    try {
                        process(cs);
                    } catch (RuntimeException ex) {
                    }
                });
            }
        }
    }

    protected void process(List<T> chunks) {
    }

}
公共抽象类JavaFXWorker扩展任务{
私有列表块=新的ArrayList();
私有最终对象锁=新对象();
私有布尔值=false;
受保护的最终作废发布(T…结果){
已同步(锁定){
addAll(Arrays.asList(results));
如果(!正在更新){
Chunk=true;
Platform.runLater(()->{
名单C;
已同步(锁定){
cs=块;
//创建新列表以避免不必要的锁定工作线程
chunks=newarraylist();
Chunk=false;
}
试一试{
过程(cs);
}捕获(RuntimeException ex){
}
});
}
}
}
受保护的无效进程(列表块){
}
}
样本使用

@Override
public void start(Stage primaryStage) {

    ListView<Integer> lv = new ListView<>();

    Button btn = new Button("Run");
    btn.setOnAction((ActionEvent event) -> {
        JavaFXWorker<Void, Integer> worker = new JavaFXWorker<Void, Integer>() {

            @Override
            protected Void call() throws Exception {
                final int maxCount = 100;

                Random random = new Random();

                int breakIndex = random.nextInt(maxCount-1)+1;

                for (int i = 0; i < breakIndex; i++) {
                    publish(i);
                }
                // some break simulating a part long part of the task with no updates
                Thread.sleep(3000);
                for (int i = breakIndex; i <= maxCount; i++) {
                    publish(i);
                }

                return null;
            }

            @Override
            protected void process(List<Integer> chunks) {
                lv.getItems().addAll(chunks);
            }

        };
        new Thread(worker).start();
    });


    Scene scene = new Scene(new VBox(btn, lv));

    primaryStage.setScene(scene);
    primaryStage.show();
}
@覆盖
公共无效开始(阶段primaryStage){
ListView lv=新建ListView();
按钮btn=新按钮(“运行”);
btn.setOnAction((ActionEvent事件)->{
JavaFXWorker=newjavafxworker(){
@凌驾
受保护的Void调用()引发异常{
最终整数最大计数=100;
随机=新随机();
int breakIndex=random.nextInt(maxCount-1)+1;
对于(int i=0;ifor(int i=breakIndex;i
任务
仅保证传递给
updateValue
的值或稍后传递的值将被设置为
value
属性。这样做是为了通过限制通知侦听器的更改数量来提高应用程序线程的性能

为什么为
messageProperty
触发绑定的次数比为
valueProperty
触发绑定的次数要多?触发次数应该相同

如上所述,无法保证更新的数量。