Multithreading Javafx任务<;可观察列表>;。updateValue仅触发第一个更改事件

Multithreading Javafx任务<;可观察列表>;。updateValue仅触发第一个更改事件,multithreading,javafx,javafx-8,Multithreading,Javafx,Javafx 8,我希望观察任务的valueProperty,并在它被updateValue()更改时采取操作。不过,更改事件似乎只在第一次更新时触发 有一节暗示重复调用UpdateValue以返回部分结果是合乎礼仪的。也许我不明白他们所说的“更新合并”是什么意思 最低限度的例子 导入javafx.application.application; 导入javafx.application.Platform; 导入javafx.beans.property.ReadOnlyObjectWrapper; 导入java

我希望观察任务的valueProperty,并在它被updateValue()更改时采取操作。不过,更改事件似乎只在第一次更新时触发

有一节暗示重复调用UpdateValue以返回部分结果是合乎礼仪的。也许我不明白他们所说的“更新合并”是什么意思

最低限度的例子
导入javafx.application.application;
导入javafx.application.Platform;
导入javafx.beans.property.ReadOnlyObjectWrapper;
导入javafx.collections.FXCollections;
导入javafx.collections.ObservableList;
导入javafx.concurrent.Task;
导入javafx.scene.scene;
导入javafx.scene.control.ListView;
导入javafx.stage.stage;
公共类主扩展应用程序{
MyTask任务=新建MyTask();
ListView ListView=新建ListView();
@凌驾
public void start(Stage primaryStage)引发异常{
primaryStage.setScene(新场景(listView));
primaryStage.show();
线程任务线程=新线程(任务);
taskThread.start();
task.valueProperty().addListener((ob,old,nw)->listView.getItems().addAll(nw));//仅激发一次。
//task.lastString.addListener(iv->listView.getItems().addAll(task.lastString.getValue());//激发每个添加
}
公共静态void main(字符串[]args){launch(args);}
}
类MyTask扩展了任务{
ObservableList=FXCollections.observableArrayList();
public ReadOnlyObjectWrapper lastString=new ReadOnlyObjectWrapper(new String());
整数maxWork=4;
@凌驾
受保护的ObservableList调用()引发异常{
对于(整数stringNo=0;stringNo{
lastString.setValue(addMe);//按预期工作。
} );
}
退货清单;
}
}

任务的
值只更改一次。最初它是
null
。在第一次迭代中,它会发生变化,因此
值==list
,在每个后续迭代中,
值==list
(即没有进一步的变化)

您可能想:

  • 通过调用
    Platform.runLater(()->list.add(addMe)),更新FX应用程序线程上的列表
  • 安排观察列表本身,而不是任务的
    属性

  • 对于稍后出现的任何人,下面是代码,经过修改以提供对listView本身的直接访问

    package demo;
    
    import javafx.application.Application;
    import javafx.application.Platform;
    import javafx.beans.property.ReadOnlyObjectWrapper;
    import javafx.collections.FXCollections;
    import javafx.collections.ListChangeListener;
    import javafx.collections.ObservableList;
    import javafx.concurrent.Task;
    import javafx.scene.Scene;
    import javafx.scene.control.ListView;
    import javafx.stage.Stage;
    
    import java.util.List;
    
    public class Main extends Application {
        MyTask task = new MyTask();
        ListView<String> listView = new ListView<>();
    
        @Override
        public void start(Stage primaryStage) throws Exception {
            primaryStage.setScene(new Scene(listView));
            primaryStage.show();
    
            task.lv = listView;
            Thread taskThread = new Thread(task);
            taskThread.start();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    
    class MyTask extends Task<ObservableList<String>> {
        ObservableList<String> list = FXCollections.observableArrayList();
        public ReadOnlyObjectWrapper<String> lastString = new ReadOnlyObjectWrapper<>(new String());
        Integer maxWork = 4;
        ListView lv;
    
        @Override
        protected ObservableList<String> call() throws Exception {
            updateValue(list); // make sure that the task's valueproperty has a value.
            Platform.runLater(() -> addMyListener());
    
    
            for (Integer stringNo = 0; stringNo < maxWork; stringNo++) {
                Thread.sleep(500);
                String addMe = new String("Thread string " + stringNo);
                list.add(addMe);
                updateProgress(stringNo, maxWork);
                updateValue(list);   // Only fires one change event
                Platform.runLater(() -> {
                    lastString.setValue(addMe); // Works as expected.
                });
            }
            return list;
        }
    
        void addMyListener() {
            ObservableList<String> obl = valueProperty().getValue();
            obl.addListener(new ListChangeListener<String>() {
                @Override
                public void onChanged(Change<? extends String> c) {
                    while (c.next()) {
                        List added = c.getAddedSubList();
                        Platform.runLater(() -> lv.getItems().addAll(added));
                    }
                }
            });
        }
    
    
    }
    
    软件包演示;
    导入javafx.application.application;
    导入javafx.application.Platform;
    导入javafx.beans.property.ReadOnlyObjectWrapper;
    导入javafx.collections.FXCollections;
    导入javafx.collections.ListChangeListener;
    导入javafx.collections.ObservableList;
    导入javafx.concurrent.Task;
    导入javafx.scene.scene;
    导入javafx.scene.control.ListView;
    导入javafx.stage.stage;
    导入java.util.List;
    公共类主扩展应用程序{
    MyTask任务=新建MyTask();
    ListView ListView=新建ListView();
    @凌驾
    public void start(Stage primaryStage)引发异常{
    primaryStage.setScene(新场景(listView));
    primaryStage.show();
    task.lv=列表视图;
    线程任务线程=新线程(任务);
    taskThread.start();
    }
    公共静态void main(字符串[]args){
    发射(args);
    }
    }
    类MyTask扩展了任务{
    ObservableList=FXCollections.observableArrayList();
    public ReadOnlyObjectWrapper lastString=new ReadOnlyObjectWrapper(new String());
    整数maxWork=4;
    ListView lv;
    @凌驾
    受保护的ObservableList调用()引发异常{
    updateValue(list);//确保任务的valueproperty具有值。
    Platform.runLater(()->addMyListener());
    对于(整数stringNo=0;stringNo{
    lastString.setValue(addMe);//按预期工作。
    });
    }
    退货清单;
    }
    void addMyListener(){
    ObservableList obl=valueProperty().getValue();
    obl.addListener(新的ListChangeListener(){
    @凌驾
    
    public void onChanged(change谢谢!你说得很对,我把任务的valueProperty误认为是任务的ObserveableList。最初的回答是:“这是代码,修改后可以直接访问列表视图本身”。为什么MyTask应该知道一些GUI元素?!这不是它的责任。紧密耦合会使架构消失,而这样做会使代码库的维护变成噩梦……重点是。MCVE不关心架构。
    package demo;
    
    import javafx.application.Application;
    import javafx.application.Platform;
    import javafx.beans.property.ReadOnlyObjectWrapper;
    import javafx.collections.FXCollections;
    import javafx.collections.ListChangeListener;
    import javafx.collections.ObservableList;
    import javafx.concurrent.Task;
    import javafx.scene.Scene;
    import javafx.scene.control.ListView;
    import javafx.stage.Stage;
    
    import java.util.List;
    
    public class Main extends Application {
        MyTask task = new MyTask();
        ListView<String> listView = new ListView<>();
    
        @Override
        public void start(Stage primaryStage) throws Exception {
            primaryStage.setScene(new Scene(listView));
            primaryStage.show();
    
            task.lv = listView;
            Thread taskThread = new Thread(task);
            taskThread.start();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    
    class MyTask extends Task<ObservableList<String>> {
        ObservableList<String> list = FXCollections.observableArrayList();
        public ReadOnlyObjectWrapper<String> lastString = new ReadOnlyObjectWrapper<>(new String());
        Integer maxWork = 4;
        ListView lv;
    
        @Override
        protected ObservableList<String> call() throws Exception {
            updateValue(list); // make sure that the task's valueproperty has a value.
            Platform.runLater(() -> addMyListener());
    
    
            for (Integer stringNo = 0; stringNo < maxWork; stringNo++) {
                Thread.sleep(500);
                String addMe = new String("Thread string " + stringNo);
                list.add(addMe);
                updateProgress(stringNo, maxWork);
                updateValue(list);   // Only fires one change event
                Platform.runLater(() -> {
                    lastString.setValue(addMe); // Works as expected.
                });
            }
            return list;
        }
    
        void addMyListener() {
            ObservableList<String> obl = valueProperty().getValue();
            obl.addListener(new ListChangeListener<String>() {
                @Override
                public void onChanged(Change<? extends String> c) {
                    while (c.next()) {
                        List added = c.getAddedSubList();
                        Platform.runLater(() -> lv.getItems().addAll(added));
                    }
                }
            });
        }
    
    
    }