【发布时间】: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 类。