【问题标题】:JavaFX table update threading architecture mismatchJavaFX 表更新线程架构不匹配
【发布时间】:2018-10-02 19:45:21
【问题描述】:

我有一个 JavaFX 表,它最终包含在网络线程上接收到的数据。

使用 Platform.runLater() 更新视图模型很简单,但它不适合我们的架构。

当前架构将应用程序分为“视图”和“网络/通信”部分。

  • View 监听模型并更新相应的组件。不了解网络。
  • Network 监听网络更新并将数据相应地写入模型。不了解 JavaFX。

所以我进退两难了。

  • 忠于架构和“关注点分离” - 网络阅读器类不应调用 Platform.runLater()

  • 为了简单起见,让网络阅读器类调用 Platform.runLater() - 可以正常工作 - 无需额外代码。

我试图用代码来说明这一点

简单的方法

只需从网络阅读器调用 Platform.runLater()

public class SimpleUpdate extends Application {
    private int clock;

    public class Item {
        private IntegerProperty x = new SimpleIntegerProperty(0);

        public final IntegerProperty xProperty() {
            return this.x;
        }

        public final int getX() {
            return this.xProperty().get();
        }

        public final void setX(final int x) {
            this.xProperty().set(x);
        }
    }

    @Override
    public void start(Stage primaryStage) throws Exception {

        ObservableList<Item> viewModel = FXCollections.observableArrayList();
        TableView<Item> table = new TableView<Item>(viewModel);
        TableColumn<Item, Integer> colX = new TableColumn<>();
        colX.setCellValueFactory(new PropertyValueFactory<Item, Integer>("x"));
        table.getColumns().add(colX);

        primaryStage.setScene(new Scene(table));
        primaryStage.show();

        new Thread(() -> {
            while (true) {
                Platform.runLater(() -> { // update on JavaFX thread
                    if (clock % 2 == 0) {
                        viewModel.add(new Item());
                        viewModel.add(new Item());
                    } else {
                        viewModel.remove(1);
                    }
                    for (Item each : viewModel) {
                        each.setX(each.getX() + 1);
                    }
                    clock++;
                });
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "Network update").start();
    }

    public static void main(String[] args) {
        launch(args);
    }

}

纯粹的方法

  • 网络阅读器线程写入自己的模型
  • 视图监听器监听网络模型并使用 JavaFX 线程同步自己的视图模型
  • 要复杂得多

代码

public class PureUpdate extends Application {
    private int clock;

    public class Item {
        private IntegerProperty x = new SimpleIntegerProperty(0);

        public final IntegerProperty xProperty() {
            return this.x;
        }

        public final int getX() {
            return this.xProperty().get();
        }

        public final void setX(final int x) {
            this.xProperty().set(x);
        }
    }

    public class ViewItem extends Item {
        private Item original;

        public ViewItem(Item original) {
            super();
            this.original = original;
            sync();
        }

        public void sync() {
            setX(original.getX());
        }

        public Item getOriginal() {
            return original;
        }
    }

    @Override
    public void start(Stage primaryStage) throws Exception {

        ObservableList<ViewItem> viewModel = FXCollections.observableArrayList();
        TableView<ViewItem> table = new TableView<ViewItem>(viewModel);
        TableColumn<ViewItem, Integer> colX = new TableColumn<>();
        colX.setCellValueFactory(new PropertyValueFactory<ViewItem, Integer>("x"));
        table.getColumns().add(colX);

        primaryStage.setScene(new Scene(table));
        primaryStage.show();

        ObservableList<Item> networkModel = FXCollections
                .synchronizedObservableList(FXCollections.observableArrayList());

        networkModel.addListener((Observable obs) -> {
            Platform.runLater(() -> {
                List<Item> alreadyKnown = new ArrayList<>();
                for (Iterator<ViewItem> it = viewModel.iterator(); it.hasNext();) {
                    ViewItem each = it.next();
                    alreadyKnown.add(each.getOriginal());
                    if (networkModel.contains(each.getOriginal())) {
                        each.sync();
                    } else {
                        it.remove();
                    }
                }
                for (Item each : networkModel.toArray(new Item[0])) {
                    if (!alreadyKnown.contains(each)) {
                        viewModel.add(new ViewItem(each));
                    }
                }
            });

        });

        new Thread(() -> {
            while (true) {
                if (clock % 2 == 0) {
                    networkModel.add(new Item());
                    networkModel.add(new Item());
                } else {
                    networkModel.remove(1);
                }
                for (Item each : networkModel) {
                    each.setX(each.getX() + 1);
                }
                clock++;
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "Network update").start();
    }

    public static void main(String[] args) {
        launch(args);
    }

}

问题。我可以在不编写额外代码的情况下实现纯方法吗?

【问题讨论】:

  • 你可能想看看在这种情况下有用的Task 类。

标签: java javafx


【解决方案1】:

让处理器将通知发布到Runnable。或Consumer&lt;T&gt;,或定义自定义@FunctionalInterface

这将使您在设计线程和对 JavaFX 或任何其他需要在特定线程上同步的框架的依赖项时更轻松地进行测试。

使用消费者的示例:

public class NetworkReader {
   private final Consumer<? super Data> consumer;

   public NetworkReader(Consumer<? super Data> consumer) {
       this.consumer = Objects.requireNonNull(consumer);
   }

   public void readStuff() {
       while (...) {
           Data data = ...;
           consumer.accept(data);
       }
   }
}

NetworkReader 将使用例如构造new NetworkReader(d -&gt; Platform.runLater(() -&gt; updateModel(d)));

当你想通过测试时,你可以这样做:

NetworkReader reader = new NetworkReader(d -> this.actuals = d);
reader.readStuff();
assertEquals(expecteds, actuals);

一个聪明的消费者可以在实际处理之前coelesc更新。

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-26
  • 2015-08-03
  • 1970-01-01
  • 2019-11-27
  • 1970-01-01
  • 2014-05-11
  • 2015-10-26
相关资源
最近更新 更多