并发任务更新复杂对象JavaFX - swingworker等效? [英] Concurrent task updating complex object JavaFX - swingworker equivalent?

查看:247
本文介绍了并发任务更新复杂对象JavaFX - swingworker等效?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to run a task in background updating intermediate results in the view.I am trying to implement MVC JavaFX application. The task is defined in the Model. I want to send to the main threath partial results in order to show them in the View. I use updateValue() to do so. Also, I define object property and a listener in the controller.

我的问题:每次updateValue()时都没有触发来自监听器的方法changed()在任务中执行。为什么?我怎么能强迫它这样做?。

My problem: The method changed() from the listener, is not being fired each time that updateValue() is executed in the Task. Why? How can I force it to do this?.

我没有找到太多复杂的例子。

I have not found much complex examples.

我是什么到目前为止:

Model.cpp

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;        
        }
   };
}

Controller.cpp

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();
}

我的问题/结论:


  1. 如何强制执行我在任务updateValue()中执行的所有时间来真正执行监听器 - 所以执行我想要绘制数据的代码。

  1. How to force to all times that I execute in the task updateValue() to really execute the listener - so execute the code where I want to plot data.

为什么fireProperty的绑定比valueProperty更多次? - 它应该是相同的次数。

Why it is more times fire the bind for the messageProperty than the valueProperty? - it should be the same number of times.

为什么我发现调试模式比正常执行时触发器的代码被触发了多次?

Why I find that the code of the listener is fired more times when debug mode than normal execution?

任何关于这个主题的好消息来源的推荐(从复杂的角度来看)都会很棒。

Any recomendation of good sources about this topic (from a complex point of view) would be great.

我正在寻找JavaFX中的东西来取代SwingWorker。

I am looking from something in JavaFX to replace SwingWorker.

最后我真正想要的是:从任务中返回一个complexObjects列表,理想情况下,updateValue()将每个对象发送一次(部分结果)

What I really whant at the end: To return a list of complexObjects from the task, and ideally, updateValue() would send the objects one per one (partial results)

我已遵循:
https://docs.oracle.com /javase/8/javafx/api/javafx/concurrent/Task.html

非常感谢任何贡献

推荐答案

任务仅保证值传递给 updateValue 或传递lat的值er将被设置为属性。这样做是为了通过限制通知监听器的更改次数来提高应用程序线程的性能。

Task only guaranties that a value passes to updateValue or a value passed later will be set to the value property. This is done to increase performance of the application thread by limiting the number of changes the listeners are notified of.


为什么它会更多次火 messageProperty 的绑定比 valueProperty ? - 它应该是相同的次数。

Why it is more times fire the bind for the messageProperty than the valueProperty? - it should be the same number of times.

如上所述,根本没有关于更新次数的保证。

As described above there simply is no guaranty about the number of updates.


为什么我发现调试模式比正常执行时更多次触发侦听器的代码?

Why I find that the code of the listener is fired more times when debug mode than normal execution?

通常,调试会使您的程序变小。来自任务的主题的更新频率越小,任务类之间的更新次数越少更新属性和跳过的数量越小。 (更新可能每帧或每隔几帧执行一次。)如果你甚至在任务中使用断点/步进器,你可能会使任务非常慢,而应用程序线程以正常速度运行。

In general debugging makes your program smaller. The smaller the update frequency from the thread of your Task, the smaller the number of updates between the times the Task class updates the properties and the smaller the number of skipped. (The updates are probably executed every frame or every few frames.) If you even use a break-point/stepper in the task, you probably make the Task extremely slow while the application thread runs at normal speed.

应该很容易实现 publish 自己使用列表来缓冲更新

It should be easy enough to implement publish on your own by using a List to buffer the updates

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) {
    }

}

样本使用

@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();
}

这篇关于并发任务更新复杂对象JavaFX - swingworker等效?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆