如何准备FXML控制器为GC

时间:2018-01-11 01:00:08

标签: javafx garbage-collection

我的申请中有问题。任何控制器都是垃圾回收。

我准备了一个,非常简单,功能清晰,但是没有从内存中删除。

@Log4j2
public class DialogOpenProjectController extends DialogPane implements Initializable, FXMLController, FXMLPane, FXMLDialogController {

    @FXML
    private ObjectProperty<ResourceBundle> languageBundle = new SimpleObjectProperty<>();

    @FXML
    private JFXTabPane TAB_PANE_OPEN_PROJECT;

    @FXML
    private JFXButton BUTTON_CONFIRM;

    private Tab tabOpenNewProject;

    private Tab tabOpenExistingProject;

    private Stage stage;
    private ChangeListener<? super ResourceBundle> languageListener = this::languageChange;
    private ChangeListener<? super Tab> selectedTabListener = this::selectedTabChanged;

    {
        tabOpenExistingProject = new Tab();
        tabOpenNewProject = new Tab();
    }

    /**
     * Initializes the controller class.
     */
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        log.trace(LogMessages.MSG_CTRL_INITIALIZATION);
        this.languageBundle.setValue(rb);
        initTabs();

        addSelectedTabListener();
        addDisableButtonListener();
        addLanguageListener();

        log.trace(LogMessages.MSG_CTRL_INITIALIZED);

    }


    @FXML
    public void cancel() {
        this.stage.close();
        clean();
    }

    @FXML
    public void confirm() {
        if (TAB_PANE_OPEN_PROJECT.getSelectionModel().getSelectedItem().equals(tabOpenNewProject)) {
            actionNewProject();

        } else if (TAB_PANE_OPEN_PROJECT.getSelectionModel().getSelectedItem().equals(tabOpenExistingProject)) {
            actionOpenProject();
        } else {

            //To to show error
        }
        this.stage.close();
        clean();

    }

    private void initTabs() {

    TAB_PANE_OPEN_PROJECT.getSelectionModel().select(tabOpenNewProject);
    }
    private void addSelectedTabListener() {
        TAB_PANE_OPEN_PROJECT.getSelectionModel().selectedItemProperty().addListener(selectedTabListener);
    }

    private void addDisableButtonListener() {
//nothing to do temporary
    }
    private void clean() {
        this.languageBundle.removeListener(languageListener);

        languageBundle.unbind();
        languageBundle.setValue(null);
        TAB_PANE_OPEN_PROJECT.getSelectionModel().selectedItemProperty().removeListener(selectedTabListener);
        TAB_PANE_OPEN_PROJECT.getSelectionModel().clearSelection();
        TAB_PANE_OPEN_PROJECT.getTabs().clear();
        BUTTON_CONFIRM.disableProperty().unbind();
        selectedTabListener = null;
        languageListener = null;
        tabOpenNewProject = null;
        tabOpenExistingProject = null;
        stage = null;
       getChildren().clear();
    }

    private void addLanguageListener() {
        this.languageBundle.addListener(languageListener);
    }

    private void languageChange(ObservableValue<? extends ResourceBundle> observable, ResourceBundle oldValue, ResourceBundle newValue) {
        reloadElements();
    }

    private String getValueFromKey(String key) {
        return this.languageBundle.getValue().getString(key);
    }

    private void reloadElements() {
        // Nothing to do
    }

    public void setStage(Stage stage) {
        this.stage = stage;
    }

    private void selectedTabChanged(ObservableValue<? extends Tab> observable, Tab oldValue, Tab newValue) {
        if (newValue.equals(tabOpenNewProject)) {
            BUTTON_CONFIRM.setText(getValueFromKey(Keys.CREATE));
        } else if (newValue.equals(tabOpenExistingProject)) {
            BUTTON_CONFIRM.setText(getValueFromKey(Keys.OPEN));
        }
    }
}

为了加载FXML文件,我使用Singleton Class ScreenManager。调用此方法来加载此对话框:

public void showNewDialog(FilesFXML fxml){

FXMLLoader loader = new FXMLLoader(getClass().getResource(fxml.toString()), context.getBundleValue());

try {
    Stage dialogStage = new Stage();
    AnchorPane dialogwindow = (AnchorPane) loader.load();
    FXMLDialogController controller = loader.getController();
    dialogStage.initModality(Modality.WINDOW_MODAL);
    dialogStage.initOwner(this.getStage());
    Scene scene = new Scene(dialogwindow);
    dialogStage.setScene(scene);
    dialogStage.setResizable(false);
    controller.setStage(dialogStage);
    dialogStage.showAndWait();


} catch (Exception ex) {
    log.error(ex.getMessage());
    log.error(ex.getCause());
    ex.printStackTrace();
}

}

我在VisualVM中检查了它,我看到这个控制器中的一个和2个lambdas(我想它是2个监听器的初始化)

但事件清除功能被称为此对话框仍在内存中,无法进行垃圾回收。我不知道如何强行删除它。它是真正的,因为它包含了我的所有控制器。

1 个答案:

答案 0 :(得分:0)

我很困惑你在问什么以及你在谈论什么。然而,如果该对话框窗口是打开的,则无法对其进行垃圾回收。

  1. JavaFX主API持有舞台的强大参考(也许是场景)。
  2. 舞台/场景持有FXML文件中指定的所有节点的强引用。
  3. 其中一些节点持有控制器的强引用,因为您在控制器中指定了操作事件处理程序。
  4. 为了使控制器符合垃圾收集的条件,你需要在某个地方打破这个链。

    最简单的方法是关闭对话框窗口。当窗口关闭时,由于JavaFX引擎不再需要管理渲染脉冲,它将释放对该阶段的引用。那时,在那个阶段的整个事情都有资格进行垃圾收集,如果没有别的东西(它本身没有资格进行垃圾收集),那么就会有很强的参考资料。