Initialize方法在Main类中的指定方法之前运行

我试图将一个对象从一个控制器传递到另一个控制器。 我传入BookViewController的rowData-object对初始化方法的工作至关重要,如果没有设置数据,那么NullPointerException确实会发生在我的情况下。

似乎initialize-method在setRowData-method之前运行。 正如我所说,initialize-method依赖于setRowData-method已执行。

我在这里错过了什么?

Main.java

public class Main extends Application { private static Stage primaryStage; private static BorderPane mainLayout; @Override public void start(Stage primaryStage) throws Exception { Main.primaryStage = primaryStage; Main.primaryStage.setTitle("BookingApp"); showMainView(); } private void showMainView() throws IOException { FXMLLoader loader = new FXMLLoader(); loader.setLocation(Main.class.getResource("MainView.fxml")); mainLayout = loader.load(); Scene scene = new Scene(mainLayout); primaryStage.setScene(scene); primaryStage.show(); } public static void showBookView(Trip rowData) throws IOException { FXMLLoader loader = new FXMLLoader(); loader.setLocation(Main.class.getResource("BookView.fxml")); BorderPane bookTrip = loader.load(); BookViewController bvc = loader.getController(); // The below method never runs.. why? bvc.setRowData(rowData); Stage bookStage = new Stage(); bookStage.setTitle("BookingApp"); bookStage.initModality(Modality.WINDOW_MODAL); bookStage.initOwner(primaryStage); Scene scene = new Scene(bookTrip); bookStage.setScene(scene); bookStage.showAndWait(); } public static void main(String[] args) { launch(args); } } 

BookViewController.java

 public class BookViewController implements Initializable { private String dbUrl = "jdbc:postgresql://localhost:5432/BookingApp"; private String dbUsername = "postgres"; private String dbPassword = "secret"; @FXML private TextField personnr; @FXML private TextField name; @FXML private TextField email; @FXML private TextField telnr; @FXML private Button addTraveler; @FXML private Button removeTraveler; @FXML private TableView travelers; @FXML private TableColumn personnrColumn; @FXML private TableColumn nameColumn; @FXML private TableColumn emailColumn; @FXML private TableColumn telnrColumn; @FXML private TableView trips; @FXML private TableColumn originColumn; @FXML private TableColumn destinationColumn; @FXML private TableColumn departureColumn; @FXML private TableColumn arrivalColumn; @FXML private TableColumn driverColumn; @FXML private TableColumn priceAmountColumn; @FXML private TableColumn seatsColumn; @FXML private Button bookTrip; private Trip rowData; private ObservableList tripData; public void setRowData(Trip rowData) { this.rowData = rowData; // The below println is never printed to the console.. System.out.println("Test"); } @Override public void initialize(URL arg0, ResourceBundle arg1) { addTraveler.setDisable(true); removeTraveler.setDisable(true); populateTravelPlan(); } @FXML private void populateTravelPlan() { try { Connection conn = DriverManager.getConnection(dbUrl, dbUsername, dbPassword); tripData = FXCollections.observableArrayList(); ResultSet rs = null; System.out.println(rowData.getTrip1()); // Here it breaks System.out.println(rowData.getTrip2()); System.out.println(rowData.getTrip3()); if(rowData.getTrip1() != 0 && rowData.getTrip2() == 0 && rowData.getTrip3() == 0) { rs = conn.createStatement().executeQuery( "select trip.tripid, connexion.origin, connexion.destination, trip.departure, trip.arrival, trip.driverpnr, trip.priceamount, trip.seats\r\n" + "from trip, connexion\r\n" + "where trip.tripid = " + rowData.getTrip1() + "\r\n" + "and trip.connexionid = connexion.connexionid\r\n" + "order by departure;"); } else if(rowData.getTrip1() != 0 && rowData.getTrip2() != 0 && rowData.getTrip3() == 0) { rs = conn.createStatement().executeQuery( "select trip.tripid, connexion.origin, connexion.destination, trip.departure, trip.arrival, trip.driverpnr, trip.priceamount, trip.seats\r\n" + "from trip, connexion\r\n" + "where trip.tripid = " + rowData.getTrip1() + "\r\n" + "and trip.connexionid = connexion.connexionid\r\n" + "union\r\n" + "select trip.tripid, connexion.origin, connexion.destination, trip.departure, trip.arrival, trip.driverpnr, trip.priceamount, trip.seats\r\n" + "from trip, connexion\r\n" + "where trip.tripid = " + rowData.getTrip2() + "\r\n" + "and trip.connexionid = connexion.connexionid\r\n" + "order by departure;"); } else if(rowData.getTrip1() != 0 && rowData.getTrip2() != 0 && rowData.getTrip3() != 0) { rs = conn.createStatement().executeQuery( "select trip.tripid, connexion.origin, connexion.destination, trip.departure, trip.arrival, trip.driverpnr, trip.priceamount, trip.seats\r\n" + "from trip, connexion\r\n" + "where trip.tripid = " + rowData.getTrip1() + "\r\n" + "and trip.connexionid = connexion.connexionid\r\n" + "union\r\n" + "select trip.tripid, connexion.origin, connexion.destination, trip.departure, trip.arrival, trip.driverpnr, trip.priceamount, trip.seats\r\n" + "from trip, connexion\r\n" + "where trip.tripid = " + rowData.getTrip2() + "\r\n" + "and trip.connexionid = connexion.connexionid\r\n" + "union\r\n" + "select trip.tripid, connexion.origin, connexion.destination, trip.departure, trip.arrival, trip.driverpnr, trip.priceamount, trip.seats\r\n" + "from trip, connexion\r\n" + "where trip.tripid = " + rowData.getTrip3() + "\r\n" + "and trip.connexionid = connexion.connexionid\r\n" + "order by departure;"); } tripData.add(new Trip(rs.getInt(1), rs.getString(2), rs.getString(3), ""+rs.getTimestamp(4), ""+rs.getTimestamp(5), rs.getString(6), ""+rs.getInt(7), ""+rs.getInt(8))); while(rs.next()) { tripData.add(new Trip(rs.getInt(1), rs.getString(2), rs.getString(3), ""+rs.getTimestamp(4), ""+rs.getTimestamp(5), rs.getString(6), ""+rs.getInt(7), ""+rs.getInt(8))); } } catch (SQLException e) { e.printStackTrace(); } trips.setItems(tripData); } } 

例外

 javafx.fxml.LoadException: /C:/Users/David/Desktop/eclipse/BookingApp1/bin/booking/BookView.fxml at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601) at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2579) at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441) at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2409) at booking.Main.showBookView(Main.java:35) at booking.MainViewController$1.handle(MainViewController.java:227) at booking.MainViewController$1.handle(MainViewController.java:1) at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86) at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238) at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191) at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59) at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58) at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74) at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54) at javafx.event.Event.fireEvent(Event.java:198) at javafx.scene.Scene$ClickGenerator.postProcess(Scene.java:3470) at javafx.scene.Scene$ClickGenerator.access$8100(Scene.java:3398) at javafx.scene.Scene$MouseHandler.process(Scene.java:3766) at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485) at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762) at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494) at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:381) at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295) at java.security.AccessController.doPrivileged(Native Method) at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$353(GlassViewEventHandler.java:417) at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389) at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:416) at com.sun.glass.ui.View.handleMouseEvent(View.java:555) at com.sun.glass.ui.View.notifyMouse(View.java:937) at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) at com.sun.glass.ui.win.WinApplication.lambda$null$147(WinApplication.java:177) at java.lang.Thread.run(Unknown Source) Caused by: java.lang.NullPointerException at booking.BookViewController.populateTravelPlan(BookViewController.java:109) at booking.BookViewController.initialize(BookViewController.java:100) at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2548) ... 39 more 

似乎initialize-method在setRowData-method之前运行。

这确实是对的。 作为执行load()一部分, FXMLLoader调用initialize()方法,这必须在你有机会调用setRowData(...)之前发生。

我在这里错过了什么?

真的没什么。

有几种可能的修复方法。 一种是简单地避免让initialize()方法依赖于传递给setRowData()的数据,并将依赖于这些数据的任何代码移动到后一种方法。 在这种情况下,这非常简单:

 public void setRowData(Trip rowData) { this.rowData = rowData; populateTravelPlan(); } @Override public void initialize(URL arg0, ResourceBundle arg1) { addTraveler.setDisable(true); removeTraveler.setDisable(true); // don't do this here: // populateTravelPlan(); } 

如果您不喜欢该解决方案,另一个选择是将控制器设置为代码而不是FXML。 简而言之,您将从FXML文件中删除fx:controller属性,然后在加载FXML时,创建一个控制器实例,调用setRowData() (或以其他方式初始化行数据,例如通过构造函数),并调用setController()FXMLLoader 。 在Passing Parameters JavaFX FXML中详细描述了该解决方案。

该解决方案的一个缺点是,如果使用Scene Builder进行FXML设计,Scene Builder将失去一些function(因为它不再知道用于创建控制器的类)。 如果要保留该function,可以使用控制器工厂。

对于该解决方案,我将修改控制器,以便将行数据传递给构造函数:

 public class BookViewController implements Initializable { // @FXML-annotated fields omitted... private final Trip rowData; public BookViewController(Trip rowData) { this.rowData = rowData ; } // remove this, it is now initialized in the constructor // public void setRowData(Trip rowData) { // this.rowData = rowData; // // The below println is never printed to the console.. // System.out.println("Test"); // } @Override public void initialize(URL arg0, ResourceBundle arg1) { addTraveler.setDisable(true); removeTraveler.setDisable(true); populateTravelPlan(); } // etc... } 

此构造函数将阻止FXMLLoader使用其默认方法创建控制器实例,因此向加载器提供控制器工厂以覆盖控制器的创建方式:

 public static void showBookView(Trip rowData) throws IOException { FXMLLoader loader = new FXMLLoader(); loader.setLocation(Main.class.getResource("BookView.fxml")); loader.setControllerFactory(type -> { if (type == BookViewController.class) { return new BookViewController(rowData); } // default behavior: need this in case there are  in the FXML try { return type.getConstructor().newInstance(); } catch (Exception exc) { // fatal... throw new RuntimeException(exc); } }); BorderPane bookTrip = loader.load(); Stage bookStage = new Stage(); bookStage.setTitle("BookingApp"); bookStage.initModality(Modality.WINDOW_MODAL); bookStage.initOwner(primaryStage); Scene scene = new Scene(bookTrip); bookStage.setScene(scene); bookStage.showAndWait(); }