从库启动的线程更新 JavaFX 控件
Update JavaFX control from thread started by a library
我有一个 JavaFX 8 应用程序。它使用一种观察者模式来对事件做出反应:
public class EventBus {
public static final EventBus INSTANCE = new EventBus();
private final Set<EventListener> listeners;
private EventBus() {
listeners = new HashSet<>();
}
public void register(EventListener listener) {
listeners.add(listener);
}
public void fire(Event event) {
listeners.forEach(listener -> listener.eventFired(event));
}
}
到目前为止,它对我的所有用例都运行良好:
- 与按钮的交互
- 来自外部控制器的事件,我用
Platform.runLater()
启动的线程观察到
- 等等
现在我想启动嵌入式 Undertow HTTP 服务器并在其中部署一个 JAX-RS 端点。每当那里有请求时,我想使用上述事件总线从该端点内触发一个事件。所以,这就是我启动 Undertow 并部署我的 JAX-RS 应用程序的方式:
UndertowJaxrsServer server = new UndertowJaxrsServer().start();
server.deploy(new MyEndpoint(eventBus));
问题是 new UndertowJaxrsServer().start()
是异步调用,它自己启动一个线程。然后当 MyEndpoint
处理一个请求并尝试触发一个事件时,它发生在那个由 Undertow 启动的线程中。
所以在事件侦听器中,如果我尝试对 UI 进行任何更新,我会得到:
java.lang.IllegalStateException: Not on FX application thread; currentThread = XNIO-1 task-1
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:236)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
at javafx.scene.Parent.onProposedChange(Parent.java:367)
at com.sun.javafx.collections.VetoableListDecorator.clear(VetoableListDecorator.java:294)
at ui.DialogManager.showDialog(DialogManager.java:109)
最后,我的问题是有没有一种方法可以显式地告诉 JavaFX 运行 UI 线程中的一段代码,即使调用堆栈来自另一个线程(我对此无法控制并且我无法控制Platform.runLater()
)。
谢谢!
如果 MyEndpoint
是你的 class 然后用 Platform.runLater()
围绕 fire(Event event)
方法的调用或更改 EventBus
class:
public class EventBus {
public static final EventBus INSTANCE = new EventBus();
private final Set<EventListener> listeners;
private EventBus() {
listeners = new HashSet<>();
}
public void register(EventListener listener) {
listeners.add(listener);
}
public void fire(Event event) {
Platform.runLater(() -> {
listeners.forEach(listener -> listener.eventFired(event));
});
}
}
我有一个 JavaFX 8 应用程序。它使用一种观察者模式来对事件做出反应:
public class EventBus {
public static final EventBus INSTANCE = new EventBus();
private final Set<EventListener> listeners;
private EventBus() {
listeners = new HashSet<>();
}
public void register(EventListener listener) {
listeners.add(listener);
}
public void fire(Event event) {
listeners.forEach(listener -> listener.eventFired(event));
}
}
到目前为止,它对我的所有用例都运行良好:
- 与按钮的交互
- 来自外部控制器的事件,我用
Platform.runLater()
启动的线程观察到 - 等等
现在我想启动嵌入式 Undertow HTTP 服务器并在其中部署一个 JAX-RS 端点。每当那里有请求时,我想使用上述事件总线从该端点内触发一个事件。所以,这就是我启动 Undertow 并部署我的 JAX-RS 应用程序的方式:
UndertowJaxrsServer server = new UndertowJaxrsServer().start();
server.deploy(new MyEndpoint(eventBus));
问题是 new UndertowJaxrsServer().start()
是异步调用,它自己启动一个线程。然后当 MyEndpoint
处理一个请求并尝试触发一个事件时,它发生在那个由 Undertow 启动的线程中。
所以在事件侦听器中,如果我尝试对 UI 进行任何更新,我会得到:
java.lang.IllegalStateException: Not on FX application thread; currentThread = XNIO-1 task-1
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:236)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
at javafx.scene.Parent.onProposedChange(Parent.java:367)
at com.sun.javafx.collections.VetoableListDecorator.clear(VetoableListDecorator.java:294)
at ui.DialogManager.showDialog(DialogManager.java:109)
最后,我的问题是有没有一种方法可以显式地告诉 JavaFX 运行 UI 线程中的一段代码,即使调用堆栈来自另一个线程(我对此无法控制并且我无法控制Platform.runLater()
)。
谢谢!
如果 MyEndpoint
是你的 class 然后用 Platform.runLater()
围绕 fire(Event event)
方法的调用或更改 EventBus
class:
public class EventBus {
public static final EventBus INSTANCE = new EventBus();
private final Set<EventListener> listeners;
private EventBus() {
listeners = new HashSet<>();
}
public void register(EventListener listener) {
listeners.add(listener);
}
public void fire(Event event) {
Platform.runLater(() -> {
listeners.forEach(listener -> listener.eventFired(event));
});
}
}