【问题标题】:Update JavaFX control from thread started by a library从库启动的线程更新 JavaFX 控件
【发布时间】:2018-03-23 16:01:43
【问题描述】:

我有一个 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 线程中运行一段代码,即使调用堆栈来自另一个(我无法控制并且我可以) t 做Platform.runLater())。

谢谢!

【问题讨论】:

    标签: javafx javafx-8 undertow undertowjaxrsserver


    【解决方案1】:

    如果MyEndpoint 是您的类,则使用Platform.runLater() 包围fire(Event event) 方法的调用或更改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));    
            });
        }
    }
    

    【讨论】:

    • 作为一种优化,您还可以在 fire 中运行检查,Platform.isFXApplicationThread(),如果不在 FX 线程上,则只需 runLater,否则立即执行。
    • 非常感谢!第一个提议(围绕fire(Event event) 的调用)运行完美!
    猜你喜欢
    • 2019-01-26
    • 2013-07-26
    • 2015-05-28
    • 1970-01-01
    • 2014-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-17
    相关资源
    最近更新 更多