在每个窗口出现后复制Property的ChangeListener

时间:2016-10-24 09:10:23

标签: java javafx changelistener

假设我们有一个带fx:include的根窗口:

<?import javafx.scene.layout.VBox?>

<VBox fx:controller="sample.StartWindowController"
      xmlns:fx="http://javafx.com/fxml" alignment="center">
    <fx:include source="startwindow.fxml"/>
</VBox>

startwindow.fxml代码:

<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.VBox?>

<VBox fx:id="mainPane" fx:controller="sample.StartWindowController"
      xmlns:fx="http://javafx.com/fxml" alignment="center">
    <Button text="Go to New Window" onAction="#goToNewWindow"/>
</VBox>

点击Button更改窗口,转到新的新窗口。它的控制器StartWindowController

package sample;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import java.io.IOException;

public class StartWindowController {

  @FXML
  VBox mainPane;

  @FXML
  private void goToNewWindow() {
    Pane parentPane = (Pane) mainPane.getParent();
    parentPane.getChildren().clear();
    try {
      parentPane.getChildren().add(FXMLLoader.load(getClass().getResource("newwindow.fxml")));
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

在我向您展示“新窗口”的视图和控制器之前,您必须知道应用程序具有带有BooleanProperty字段的Singleton类。代码MySingleton

package sample;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;

public class MySingleton {

  private static MySingleton instance;
  private BooleanProperty booleanProperty;

  private MySingleton() {
    booleanProperty = new SimpleBooleanProperty(false);
  }

  public static MySingleton getInstance() {
    if (instance == null) {
      instance = new MySingleton();
    }
    return instance;
  }

  public boolean isBooleanProperty() {
    return booleanProperty.get();
  }

  public BooleanProperty booleanPropertyProperty() {
    return booleanProperty;
  }
}

newwindow.fxml代码:

<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.VBox?>

<VBox fx:id="mainPane" fx:controller="sample.NewWindowController"
      xmlns:fx="http://javafx.com/fxml" alignment="center">
    <Button text="Change BooleanProperty" onAction="#changeBooleanProperty"/>
    <Button text="Back" onAction="#goBack"/>
</VBox>

在“新窗口”创建过程中,我在控制器的MySingleton方法中为BooleanProperty的{​​{1}}添加了一个监听器。新侦听器的代码引用非静态控制器的私有方法initializeprintMessage代码:

NewWindowController

现在,问题。假设第一步是进入“新窗口”:
每次“后退”后 - &gt; “转到新窗口”序列,当我点击“更改布尔属性”时,有“{1}}打印”布尔属性已更改!“,其中package sample; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.scene.layout.Pane; import javafx.scene.layout.VBox; import java.io.IOException; public class NewWindowController { private MySingleton mySingleton; @FXML VBox mainPane; private int duplicateCounter = 1; @FXML private void initialize() { System.out.println("Initializing New Window's Controller."); System.out.println("Duplicate counter: " + duplicateCounter); mySingleton = MySingleton.getInstance(); mySingleton.booleanPropertyProperty().addListener( (observable, oldValue, newValue) -> printMessage()); duplicateCounter++; } @FXML private void changeBooleanProperty() { mySingleton.booleanPropertyProperty().setValue(!mySingleton.booleanPropertyProperty().getValue()); } @FXML private void goBack() { Pane parentPane = (Pane) mainPane.getParent(); parentPane.getChildren().clear(); try { parentPane.getChildren().add(FXMLLoader.load(getClass().getResource("startwindow.fxml"))); } catch (IOException e) { e.printStackTrace(); } } private void printMessage() { System.out.println("Boolean property changed!"); } } 是”开始窗口“的数量 - &gt; “新窗口”转换(从i+1开始)。为什么不只有一个印刷品?

我知道每次启动“新窗口”时,应用程序都会向i添加新的侦听器,问题可能是由许多属性的侦听器引起的。但是如果在一个新的监听器代码中我引用窗口转换后销毁的对象的非静态方法怎么可能呢?

我想“也许控制器没有被破坏?也许0方法以我不理解的方式工作,而控制器的对象仍然存在?”正如您可能看到的那样,我添加了一个额外的变量BooleanProperty,该变量在initialize方法的末尾递增。但每次都是duplicateCounter,所以我假设创建了全新的initialize对象。

如何防止1听众重复?

1 个答案:

答案 0 :(得分:2)

  

但是如果在一个新的监听器代码中我引用窗口转换后销毁的对象的非静态方法怎么可能呢?

  

我想“也许控制器没有被破坏?也许initialize方法以我不理解的方式工作,而控制器的对象仍然存在?”正如您可能看到的那样,我添加了一个额外的变量duplicateCounter,该变量在initialize方法的末尾递增。但每次都是1,所以我假设创建了全新的NewWindowController对象。

确实每次加载fxml时都会创建一个新的控制器,但是旧的控制器不会被“销毁”(可用于垃圾收集),因为仍然存在对该对象的引用:

MySingleton将实例存储在静态成员中,使其无法用于垃圾回收。此实例包含对BooleanProperty的引用,其中包含对侦听器的引用,该引用包含对NewWindowController的引用。

要仅打印一次消息,您必须取消注册监听器:

private final ChangeListener<Boolean> listener = (observable, oldValue, newValue) -> printMessage();

@FXML private void initialize() {
    ...
    mySingleton.booleanPropertyProperty().addListener(listener);
    ...
}

...

@FXML private void goBack() {
    // remove listener
    MySingleton.getInstance().booleanPropertyProperty().removeListener(listener);        
    ...
}