核心问题:如果绑定属性在声明绑定属性的initialize()方法之外更新,则不会触发Binding对象失效侦听器。
以在initialize() UI控制器类中声明的这个JavaFX方法为例:
@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的TextField的text属性的ChangeListener,以及一个当它变得无效时请求计算StringBinding的ChangeListener。
如果在初始化方法中编辑stringProperty值,则会触发stringProperty和StringBinding更改侦听器,而如果从UI编辑stringProperty值,则只触发stringBinding更改侦听器。
有人能解释一下为什么会发生这种事吗?
发布于 2019-04-27 19:17:09
由于不存在对由StringBinding创建的Bindings.createStringBinding的强引用,因此最终将被垃圾收集。一旦发生这种情况,您添加的侦听器将与其一起被垃圾收集。
我不认为这是因为
Binding对象通过InvalidationListener监听它们的依赖项(Observable对象),而Obsevable.addListener(InvalidationListener)文档指出,“可观察到的存储对侦听器的强烈引用,这将防止侦听器被垃圾收集,并可能导致内存泄漏。”
这是正确的,但是看看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;
}
}如您所见,添加到依赖项(即Observables)的侦听器实例是一个WeakListener,并且只维护对Binding的弱引用。这允许垃圾收集Binding,即使它没有被正确地处理。这样做是为了帮助防止内存泄漏,如果Binding已经超出了范围,但是Observable没有。
换句话说,Observable维护对InvalidationListener的强引用,而InvalidationListener维护对Binding的弱引用。
这类行为记录在“远程”位置,包括Property#bind(ObservableValue)。
为此
Property创建单向绑定。 请注意,JavaFX具有通过弱侦听器实现的所有绑定调用。这意味着绑定属性可以被垃圾收集并停止更新。
向
Binding发出信号,表示它将不再被使用,任何引用都可以删除。此方法的调用通常导致绑定停止,通过注销侦听器来观察其依赖关系。实现是可选的。 我们实现中的所有绑定都使用WeakInvalidationListener实例,这意味着通常不需要处理绑定。但是,如果计划在不支持WeakReferences的环境中使用应用程序,则必须释放未使用的Binding,以避免内存泄漏。
注意:实现似乎没有使用WeakInvalidationListener__,但是效果是相同的。
https://stackoverflow.com/questions/55879079
复制相似问题