代码之家  ›  专栏  ›  技术社区  ›  geometrikal

在javafx中父属性更改时清理绑定并更改嵌套属性上的侦听器

  •  0
  • geometrikal  · 技术社区  · 6 年前

    我有一个模特班 SimpleXXXXProperty 财产Javafx GUI元素使用绑定或更改侦听器进行更新,例如。

    textField.textProperty().bind(myModel.myModelStatus());
    

    myModel.myModelStatus().addListener((obj,oldv.newv) -> { update here });
    

    当模型类的实例更改时,我重新绑定控件并再次添加侦听器然而,通过内存使用,我可以看到旧模型仍然存在于内存中。

    要删除对模型的所有引用以便对其进行清理,我需要做什么?

    • 重新绑定前解除绑定
    • 删除侦听器
    • 两者

    当父属性更改时,是否有更自动的方法更新嵌套属性上的绑定和侦听器?

    1 回复  |  直到 6 年前
        1
  •  5
  •   isnot2bad    6 年前

    要撤消对模型的绑定(包括侦听器)时要考虑的要点:

    • 无向绑定( p1.bind(p2) )在再次绑定同一属性时自动解除绑定(例如。 p1.bind(p3) ),但明确地做并不伤害( p1.unbind() )中。
    • 双向绑定( p1.bindBidirectional(p2) Bindings.bindBidirectional(p1, p2) )必须明确地解除绑定( p1.unbindBidirectional(p2) Bindings.unbindBidirectional(p1, p2) )中。
    • 必须注销侦听器( prop.removeListener(l) )中。

    第三个是棘手的部分,因为监听器通常被实现为lambda表达式或方法引用不幸的是,lambda表达式以及方法引用(!)是 常数:

    // lambdas are not constant
    InvalidationListener l1 = obs -> {};
    InvalidationListener l2 = obs -> {};
    
    assert l1 != l2; // they are NOT identical!
    

    嗯,这对于lambdas来说可能是显而易见的,但是对于方法引用也是如此,这真的很烦人:

    // method references are not constant
    Runnable runnable1 = this::anyMethod;
    Runnable runnable2 = this::anyMethod;
    
    assert runnable1 != runnable2; // they are NOT identical!
    

    这意味着,如果希望能够注销lambda表达式或简单方法引用,则不能将其注册为侦听器:

    // if you register listeners on a property like that...
    label.textProperty().addListener(obs -> System.out.println(obs));
    label.textProperty().addListener(this::handleLabelInvalid);
    
    // ...these calls WON'T remove them due to the inequality shown above!
    label.textProperty().removeListener(obs -> System.out.println(obs));
    label.textProperty().removeListener(this::handleLabelInvalid);
    

    解决方案

    您必须自己存储对lambda表达式或方法引用的引用我使用final字段:

    public class MyClass {
        // store references for adding/removal
        private final InvalidationListener l1 = this::handleLabelInvalid;
        private final InvalidationListener l2 = obs -> System.out.println(obs);
    
        ...
    
        public void bind() {
            label.textProperty().addListener(l1);
            label.textProperty().addListener(l2);
        }
    
        public void unbind() {
            label.textProperty().removeListener(l1);
            label.textProperty().removeListener(l2);
        }
    
        private void handleLabelInvalid(Observable observable) { ... }
    }