从库启动的线程更新JavaFX控件

时间:2017-10-11 20:52:19

标签: javafx javafx-8 undertow undertowjaxrsserver

我有一个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$2.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())。

谢谢!

1 个答案:

答案 0 :(得分:2)

如果MyEndpoint是您的班级,则使用fire(Event event)或更改Platform.runLater()类围绕调用EventBus方法:

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