启动时,我的JavaFX应用程序会触发两个后台任务,一个用于初始化数据库,另一个用于对电子邮件服务器进行身份验证。每个任务都有一个布尔属性,表示成功完成。完成这两项任务后,我想开始第三项任务,开始轮询新电子邮件。
我以为我可以使用javafx.beans.binding.Bindings.and()
来组合这两项任务的结果,但它并没有解雇。这是一些代码:
BooleanBinding databaseInitializedProperty = NotesLocalDatabase.initializationStateProperty().isEqualTo( State.SUCCEEDED );
BooleanProperty isLoggedInProperty = loginPanel.isLoggedInProperty();
databaseInitializedProperty.addListener( (value, oldVal, newVal ) -> {
if( newVal ) log.info( "DATABASE INITIALIZED" ); } );
isLoggedInProperty.addListener( (value, oldVal, newVal ) -> {
if( newVal ) log.info( "IS LOGGED IN" ); } );
Bindings.and( databaseInitializedProperty, isLoggedInProperty ).addListener( (value, oldVal, newVal) -> {
log.info( "COMPOUND BINDING CHANGED: " + value + ", " + oldVal + ", " + newVal );
if( newVal ) {
log.info( "Login and database initialization both complete. Starting message check service." );
startUpdates();
}
} );
我知道我的属性工作正常,因为我在日志中看到“DATABASE INITIALIZED”和“IS LOGGED IN”。但是,我从未见过“复合约束变更”。从阅读文档开始,我认为只要属性发生变化,就会触发Bindings.and()绑定上的更改侦听器。那不是这样吗?
答案 0 :(得分:3)
您正在使用此版本的另一个版本:Bidirectional JavaFX Binding is destroyed by unrelated code
问题是,Bindings.and(...)
的结果在属性更改时已超出范围。这使它有资格进行垃圾收集。假设你的任务消耗足够的内存来强制垃圾收集器运行是不合理的,因此绑定会被破坏。
举一个简单的例子,在调用System.gc();
的情况下运行以下代码:
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
public class BindingTest {
public static void main(String[] args) {
BooleanProperty x = new SimpleBooleanProperty(false);
BooleanProperty y = new SimpleBooleanProperty(false);
x.addListener((obs, oldX, newX) -> System.out.printf("x changed from %s to %s%n", oldX, newX));
y.addListener((obs, oldY, newY) -> System.out.printf("y changed from %s to %s%n", oldY, newY));
Bindings.and(x, y).addListener((obs, oldXAndY, newXAndY) -> System.out.printf("x&y changed from %s to %s%n", oldXAndY, newXAndY));
x.set(true);
// System.gc();
y.set(true);
}
}
修复是强制绑定保持在范围内。您可能需要(有点不自然地)将其变为某个实例变量:
public class SomeClass {
private BooleanBinding initializationComplete ;
public void whereverYouHadThisCodeBefore() {
// ..
initializationComplete = Bindings.and(databaseInitializedProperty, isLoggedInProperty);
initializationComplete.addListener(...);
}
}