2016-10-24 41 views
0

假設我們有一個根窗口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(); 
    } 
    } 
} 

之前,我告訴你查看和「新窗口」的控制器,你要知道,一個應用程序有一個Singleton類BooleanProperty領域。的MySingleton代碼:

newwindow.fxml
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; 
    } 
} 

代碼:

<?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> 

在 '新窗口' 創建我的控制器的initialize方法的監聽器添加到MySingletonBooleanProperty。新的監聽者代碼引用非靜態控制器的私有方法printMessage。​​的代碼:

現在,問題所在。假設第一步進入「新窗口」:
每「返回」 - >「轉到新窗口」序列後,當單擊「更改布爾屬性」時,有i+1打印出「布爾屬性已更改!」,其中i是'開始窗口' - >'新窗口'轉換的編號(從0開始)。爲什麼不只有一個打印?

我意識到每次啓動「新窗口」時,應用程序都會向BooleanProperty添加新偵聽器,問題可能是由許多屬性的偵聽器引起的。但是,如果在新的偵聽器代碼中引用窗口轉換後銷燬的對象的非靜態方法,這怎麼可能?

我以爲「也許控制器沒有被銷燬?也許initialize方法以我不明白的方式工作,控制器的對象仍然存在?正如你可能看到的,我添加了一個額外的變量,duplicateCounter,它在initialize方法的末尾增加。但是每次都是1,所以我假設全新的​​對象被創建。

如何防止BooleanProperty聽衆重複?

回答

2

但是,如果在新的偵聽器代碼中引用窗口轉換後銷燬的對象的非靜態方法,這怎麼可能?

我想:「也許控制器不被破壞?也許initialize法的方式,我不理解和控制的對象是仍然存在的工作?」正如你可能看到的,我添加了一個額外的變量,duplicateCounter,它在initialize方法的末尾增加。但是每次都是1,所以我假設全新的​​對象被創建。

確實是一個新的控制器創建每次FXML被加載,但舊的不「破壞」(可進行垃圾回收),因爲仍然有對象參考時間:

MySingleton將實例存儲在靜態成員中,使其不可用於垃圾回收。此實例包含對BooleanProperty的引用,其中包含對偵聽器的引用,其中包含對​​的引用。

僅打印消息一次,你必須註銷監聽器:

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);   
    ... 
}