【发布时间】:2014-10-01 07:48:38
【问题描述】:
我将几个 JFXPanels 嵌入到 Swing 应用程序中,当 JFXPanel 不再可见时,JavaFX 线程终止。这是有问题的,因为在 JavaFX 线程死亡后创建另一个 JFXPanel 不会启动另一个 JavaFX 线程,因此 JFXPanel 将是空白的。
据我所知,JFXPanel ctor 通过调用来启动 JavaFX 线程:
PlatformImpl.startup(new Runnable() {
@Override public void run() {
// No need to do anything here
}
});
稍后,一旦JFXPanel 有一个父组件,它的addNotify 方法就会被调用,该方法调用registerFinishListener,它用PlatformImpl 注册一个PlatformImpl.FinishListener()。注册FinishListener 的行为可以防止在调用PlatformImpl.checkIdle() 时JavaFX 线程死亡。
当JFXPanel 不再可见时,它的removeNotify 方法被调用,该方法调用deregisterFinishListener():
private synchronized void deregisterFinishListener() {
if (instanceCount.decrementAndGet() > 0) {
// Other JFXPanels still alive
return;
}
PlatformImpl.removeListener(finishListener);
finishListener = null;
}
当instanceCount 为零时,FinishListener 被删除,这会导致PlatformImpl 在以下代码中调用PlatformImpl.tkExit,从而导致 JavaFX 线程终止:
private static void notifyFinishListeners(boolean exitCalled) {
// Notify listeners if any are registered, else exit directly
if (listenersRegistered.get()) {
for (FinishListener l : finishListeners) {
if (exitCalled) {
l.exitCalled();
} else {
l.idle(implicitExit);
}
}
} else if (implicitExit || platformExit.get()) {
tkExit();
}
}
我发现解决此问题的唯一方法是在 Swing 应用程序开始时调用 Platform.setImplicitExit(false),这样 JavaFX 线程就不会自动终止。此修复需要在应用程序退出时调用 Platform.exit(),否则 JavaFX 线程将阻止进程停止。
这似乎是 JavaFX-Swing 互操作中的一个错误,或者至少应该修改互操作文档以通过讨论 Platform.setImplicitExit(false) 来解决这个问题。
另一种解决方案是在创建另一个 JFXPanel 但被PlatformImpl.startup(Runnable) 阻止时允许创建新的 JavaFX 线程:
if (initialized.getAndSet(true)) {
// If we've already initialized, just put the runnable on the queue.
runLater(r);
return;
}
我错过了什么吗?
【问题讨论】:
-
感谢您提供这段代码:'''Platform.setImplicitExit(false)。''' 我的 javafx 线程正在死去(仍然不知道为什么),但您提供的代码修复了它。我的用例是,每当有人更改下拉列表中的某些内容时,我都会删除旧的 javafxpanel 并添加一个新的。
标签: java swing javafx interop javafx-8