当前位置: 首页 > 知识库问答 >
问题:

绑定对象不在FXML UI控制器initialize()方法之外工作

姚新霁
2023-03-14

核心问题:如果绑定属性在声明绑定属性的initialize()方法之外更新,则binding对象无效侦听器不会触发。

以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,它依赖于TextField的text属性,称为StringProperty,并声明了一个ChangeListener,它在StringBinding无效时请求计算。

如果我在initialize方法中编辑StringProperty值,则会触发StringPropertyStringBinding更改侦听器,而如果我从UI编辑StringProperty值,则只会触发StringBinding更改侦听器。

有人能解释一下为什么会这样吗?

共有1个答案

乐正浩宕
2023-03-14

由于不存在对bindings.createStringBinding创建的StringBinding的强引用,因此它最终将被垃圾回收。一旦发生这种情况,您添加的侦听器将与它一起被垃圾回收。

我不认为这是重点,因为绑定对象通过InvalidationListener侦听它们的依赖项(Observable对象),并且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;
    }
}

如您所见,添加到依赖项的侦听器实例(即可观察)是WeakListener,并且只维护对绑定的弱引用。这允许对绑定进行垃圾回收,即使它没有被正确释放。这样做是为了在绑定超出范围但可观察没有超出范围的情况下防止内存泄漏。

换句话说,Observable维护对InvalidationListener的强引用,但InvalidationListener维护对绑定的弱引用。

这种行为记录在“远程”位置,包括属性#bind(ObservableValue):

为此属性创建单向绑定。

注意,JavaFX的所有绑定调用都是通过弱监听器实现的。这意味着绑定属性可以被垃圾回收并停止更新。

 类似资料:
  • 问题内容: 我昨天在JavaFX中构建了一个小应用程序。我想在Controller类中获取应用程序的场景。每次尝试在控制器类中获取场景时,都会出错。我可以在Controller类的Button上设置OnKeyPressed方法,效果很好。但是,只有在选择Button后,它才能正常工作。我只能在Main类方法replaceSceneContent中获得场景。我已经读过这个问题,但是我在initial

  • 我昨天在JavaFX中构建了一个小应用程序。我想在Controller类中获取应用程序的场景。每次我试图在控制器类中获取场景时,我都会出错。我可以在Controller类中的Button上设置OnKeyPested-method,工作正常。但是只有当按钮被选中时,它才工作正常...我可以只在Main类方法replace eSceneContent中获取场景。我已经读过这个问题了,但是我在初始化方法

  • 问题内容: 我使用Angular组件(this的第一个示例)。当我在组件中绑定对象时,可以在模板中访问它,但不能在控制器中访问它。 js: 的HTML: 模板html(在这里有效): 错误: ReferenceError:未定义英雄 Plunker:https://plnkr.co/edit/U9CJLs6jgrlsZH6tUdr0 问题答案: 您将在上下文中获得价值 虽然以上行不通。因为它不会在

  • 在此代码中: } 我不明白为什么它在initialise()中有一个值,但在start中却是空的。调试时,很明显,initialize()是由FXMLLOader从start()内部调用的 我本来打算发布fxml,但它似乎不起作用,正如预览中没有显示的那样。无论如何,它是一个真正的基本文件,一个BordePane和一个工具栏。 有线索吗?

  • 我正在我的一个项目中使用自动装配。在控制器中运行良好,但我需要在其他类中使用相同的自动装配对象,该类用作石英的任务类。自动装配在那里不起作用。 我尝试了下面列出的这段代码,但没有成功。在所有尝试中,它都为获取。 请提出解决方案,谢谢。

  • 本文向大家介绍Laravel框架路由和控制器的绑定操作方法,包括了Laravel框架路由和控制器的绑定操作方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Laravel框架路由和控制器的绑定操作方法。分享给大家供大家参考,具体如下: 路由和控制器的关系 路由文件地址在\app\Http\routes.php,我们来看两种不同的路由。 以上均为绑定匿名函数的路由,虽然可以返回视图,也可以