核心问题:如果绑定属性在声明它们的Binding
方法之外更新,则不会触发initialize()
对象失效侦听器。
采用在JavaFX UI控制器类中声明的initialize()
方法:
@FXML
private void initialize() {
final StringProperty stringProperty = textField.textProperty();
stringProperty.addListener(
(observable, oldValue, newValue) -> System.out.println("stringProperty value: " + newValue));
Bindings.createStringBinding(() -> "PREFIX - " + stringProperty.getValue(), stringProperty).addListener(
(observable, oldValue, newValue) -> System.out.println("StringBinding value: " + newValue));
// Editing stringProperty value inside initialize() method
stringProperty.setValue("u");
stringProperty.setValue("ua");
stringProperty.setValue("ua");
stringProperty.setValue("uaa");
}
如您所见,我声明了一个StringBinding
,它依赖于一个名为stringProperty
的TextField的text属性,而一个ChangeListener
则请求计算{{1} }无效。
如果我在初始化方法中编辑StringBinding
值,则stringProperty
和stringProperty
的更改侦听器都会被触发,而如果我从UI编辑StringBinding
的值,则仅{ {1}}更改侦听器已触发。
有人可以解释一下为什么会这样吗?
答案 0 :(得分:0)
由于不存在对StringBinding
创建的Bindings.createStringBinding
的强烈引用,因此最终将被垃圾回收。一旦发生这种情况,您添加的侦听器将随之被垃圾收集。
我认为这不是重点,因为
Binding
对象通过Observable
监听其依赖项(InvalidationListener
对象),并且Obsevable.addListener(InvalidationListener)
文档指出“ Observable存储了对侦听器的强大引用,这将防止侦听器被垃圾回收,并可能导致内存泄漏。”
这是真的,但是请看一下XXXBinding
类使用的侦听器实现:
/*
* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.javafx.binding;
import java.lang.ref.WeakReference;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.WeakListener;
import javafx.beans.binding.Binding;
public class BindingHelperObserver implements InvalidationListener, WeakListener {
private final WeakReference<Binding<?>> ref;
public BindingHelperObserver(Binding<?> binding) {
if (binding == null) {
throw new NullPointerException("Binding has to be specified.");
}
ref = new WeakReference<Binding<?>>(binding);
}
@Override
public void invalidated(Observable observable) {
final Binding<?> binding = ref.get();
if (binding == null) {
observable.removeListener(this);
} else {
binding.invalidate();
}
}
@Override
public boolean wasGarbageCollected() {
return ref.get() == null;
}
}
如您所见,添加到依赖项(即Observable
)的侦听器实例是WeakListener
,并且仅维护对Binding
的弱引用。即使未正确处理Binding
,也可以将其Binding
进行垃圾回收。这样做是为了防止在Observable
超出范围而Observable
不在范围内的情况下发生内存泄漏。
换句话说,InvalidationListener
维持对InvalidationListener
的强引用,而Binding
维持对Property
的弱引用。
这种行为记录在“远程”位置,包括Property#bind(ObservableValue)
:
为此
Binding
创建一个单向绑定。请注意,JavaFX具有通过弱侦听器实现的所有绑定调用。这意味着可以对垃圾属性进行垃圾收集,并阻止其更新。
WeakInvalidationListener
上将不再使用它的信号,并且可以删除任何引用。调用此方法通常会导致绑定停止,以通过注销其侦听器来观察其依赖性。该实现是可选的。我们的实现中的所有绑定都使用
WeakReferences
的实例,这意味着通常不需要处理绑定。但是,如果您打算在不支持Binding
的环境中使用应用程序,则必须处置未使用的WeakInvalidationListener
以避免内存泄漏。
注意:该实现似乎未使用{{1}},但效果是相同的。