JavaFX FXML controller - constructor vs initialize method

JavaJavafx

Java Problem Overview


My Application class looks like this:

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

The FXMLLoader creates an instance of the corresponding controller (given in the FXML file via fx:controller) by invoking first the default constructor and then the initialize method:

public class MainViewController {

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

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

The output is:

first
second

So, why does the initialize method exist? What is the difference between using a constructor or the initialize method to initialize the controller required things?

Thanks for your suggestions!

Java Solutions


Solution 1 - Java

In a few words: The constructor is called first, then any @FXML annotated fields are populated, then initialize() is called.

This means the constructor does not have access to @FXML fields referring to components defined in the .fxml file, while initialize() does have access to them.

Quoting from the Introduction to FXML:

> [...] the controller can define an initialize() method, which will be called once on an implementing controller when the contents of its associated document have been completely loaded [...] This allows the implementing class to perform any necessary post-processing on the content.

Solution 2 - Java

The initialize method is called after all @FXML annotated members have been injected. Suppose you have a table view you want to populate with data:

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

Solution 3 - Java

In Addition to the above answers, there probably should be noted that there is a legacy way to implement the initialization. There is an interface called Initializable from the fxml library.

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

Parameters:

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. 

And the note of the docs why the simple way of using @FXML public void initialize() works:

NOTE This interface has been superseded by automatic injection of location and resources properties into the controller. FXMLLoader will now automatically call any suitably annotated no-arg initialize() method defined by the controller. It is recommended that the injection approach be used whenever possible.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmrbelaView Question on Stackoverflow
Solution 1 - JavaNikos ParaskevopoulosView Answer on Stackoverflow
Solution 2 - JavaItaiView Answer on Stackoverflow
Solution 3 - JavagkhaosView Answer on Stackoverflow