Контроллер JavaFX FXML - конструктор против метода инициализации

Мой Application класс выглядит так:

public class Test extends Application {

    private static Logger logger = LogManager.getRootLogger();

    @Override
    public void start(Stage primaryStage) throws Exception {

        String resourcePath = "/resources/fxml/MainView.fxml";
        URL location = getClass().getResource(resourcePath);
        FXMLLoader fxmlLoader = new FXMLLoader(location);

        Scene scene = new Scene(fxmlLoader.load(), 500, 500);

        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

FXMLLoader создает экземпляр соответствующего контроллера (приведенный в FXML подать через fx:controllerвызывая сначала конструктор по умолчанию, а затем initialize метод:

public class MainViewController {

    public MainViewController() {
        System.out.println("first");
    }

    @FXML
    public void initialize() {
        System.out.println("second");
    }
}

Выход:

first
second

Итак, почему initialize метод существует? В чем разница между использованием конструктора или initialize способ инициализации контроллера необходимых вещей?

Спасибо за ваши предложения!

2 ответа

В двух словах: сначала вызывается конструктор, затем любой @FXML аннотированные поля заполняются, затем initialize() называется. Таким образом, конструктор не имеет доступа к @FXML поля, относящиеся к компонентам, определенным в файле.fxml, а initialize() действительно имеет к ним доступ.

Цитата из введения в FXML:

[...] контроллер может определить метод initialize(), который будет вызываться один раз на реализующем контроллере, когда содержимое его связанного документа будет полностью загружено [...] Это позволяет классу реализации выполнять любую необходимую запись -обработка контента.

initialize Метод вызывается в конце концов @FXML аннотированные участники были введены. Предположим, у вас есть табличное представление, которое вы хотите заполнить данными:

class MyController { 
    @FXML
    TableView<MyModel> tableView; 

    public MyController() {
        tableView.getItems().addAll(getDataFromSource()); // results in NullPointerException, as tableView is null at this point. 
    }

    @FXML
    public void initialize() {
        tableView.getItems().addAll(getDataFromSource()); // Perfectly Ok here, as FXMLLoader already populated all @FXML annotated members. 
    }
}

В дополнение к приведенным выше ответам, вероятно, следует отметить, что существует лучший способ осуществить инициализацию. Есть интерфейс Initializable из библиотеки fxml.

import javafx.fxml.Initializable;

class MyController implements Initializable {
    @FXML private TableView<MyModel> tableView;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        tableView.getItems().addAll(getDataFromSource());
    }
}

Параметры:

location - The location used to resolve relative paths for the root object, or null if the location is not known.
resources - The resources used to localize the root object, or null if the root object was not localized. 

И примечание документов, почему простой способ использования @FXML public void initialize() работает:

NOTE Этот интерфейс был заменен автоматическим введением свойств местоположения и ресурсов в контроллер. FXMLLoader теперь будет автоматически вызывать любой соответствующим образом аннотированный метод no-arg initialize(), определенный контроллером. Рекомендуется использовать инъекционный подход всякий раз, когда это возможно.

Другие вопросы по тегам