Controlador JavaFX FXML - constructor vs método de inicialización

84

Mi Applicationclase se ve así:

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

El FXMLLoadercrea una instancia del controlador correspondiente (dado en el FXMLarchivo a través de fx:controller) invocando primero el constructor predeterminado y luego el initializemétodo:

public class MainViewController {

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

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

La salida es:

first
second

Entonces, ¿por qué existe el initializemétodo? ¿Cuál es la diferencia entre usar un constructor o el initializemétodo para inicializar las cosas requeridas por el controlador?

¡Gracias por tus sugerencias!

mrbela
fuente

Respuestas:

124

En pocas palabras: primero se llama al constructor, luego @FXMLse rellenan los campos anotados y luego initialize()se llama. Por lo tanto, el constructor NO tiene acceso a los @FXMLcampos que se refieren a los componentes definidos en el archivo .fxml, mientras que initialize()sí tiene acceso a ellos.

Citando de la Introducción a FXML :

[...] el controlador puede definir un método initialize (), que se llamará una vez en un controlador de implementación cuando el contenido de su documento asociado se haya cargado por completo [...] Esto permite que la clase de implementación realice cualquier publicación necesaria -procesamiento del contenido.

Nikos Paraskevopoulos
fuente
2
No entiendo. La forma en que lo hace ha terminado FXMLLoader, ¿verdad? Así que no veo ningún beneficio en esperar el initialize()método -. Tan pronto como se carga el FXML, el siguiente código tiene acceso a las @FXMLvariables. Claro, lo hace en el método de inicio y no en el constructor, pero ¿ initialize()aportaría algún beneficio en su caso?
codepleb
90

El initializemétodo se llama después de que @FXMLse hayan inyectado todos los miembros anotados. Suponga que tiene una vista de tabla que desea completar con datos:

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. 
    }
}
Itai
fuente
11

Además de las respuestas anteriores, probablemente debería tenerse en cuenta que existe una forma heredada de implementar la inicialización. Hay una interfaz llamada Initializable de la biblioteca 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());
    }
}

Parámetros:

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. 

Y la nota de los documentos por qué funciona la forma simple de usar @FXML public void initialize():

NOTEEsta interfaz ha sido reemplazada por la inyección automática de propiedades de ubicación y recursos en el controlador. FXMLLoader ahora llamará automáticamente a cualquier método initialize () no-arg adecuadamente anotado definido por el controlador. Se recomienda que se utilice el método de inyección siempre que sea posible.

gkhaos
fuente