Reputation: 283
Probably I miss somehting out, but I'm struggeling to find a solution how I can pass dependencies like an instance of my event bus and some service interfaces to my javafx application.
I got an UI-Init class which does not much more than starting the application and receiving some dependencies for the UI like an eventBus:
public class Frontend {
public Frontend(MBassador<EventBase> eventBus) {
Application.launch(AppGui.class);
}
My AppGui class extends Application and loads an FXML:
public class AppGui extends Application {
private Stage primaryStage;
private GridPane rootLayout;
@Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
try {
// Load root layout from fxml file.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("RootLayout.fxml"));
rootLayout = (GridPane) loader.load();
// Show the scene containing the root layout.
Scene scene = new Scene(rootLayout);
scene.setFill(null);
primaryStage.setScene(scene);
RootLayoutController rootController = loader.getController();
rootController.init(/*here I would like to inject my eventBus*/);
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
Now, how can I pass my eventBus and other service interfaces to this controller? I've read about using DI frameworks like guice (How can JavaFX controllers access other services?) or afterburner.fx to use it. But even if I use guice for the rest of my application, somehow I need to pass the Injector instance to the JavaFX application?.
But Application.launch(AppGui.class); is static and internally creates an AppGui instance on the javafx thread, which I don't get access to. So how I can inject dependencies to my AppGui object without using static variables?
Upvotes: 3
Views: 1992
Reputation: 40298
Here is what I do:
The Application
class has a couple of lifecycle callbacks, init()
and stop()
.
From the Javadoc:
public void init() throws java.lang.Exception
The application initialization method. This method is called immediately after the Application class is loaded and constructed. An application may override this method to perform initialization prior to the actual starting of the application.
public void stop() throws java.lang.Exception
This method is called when the application should stop, and provides a convenient place to prepare for application exit and destroy resources.
Also from the Javadocs, the lifecycle:
- Constructs an instance of the specified
Application
class- Calls the
init()
method- Calls the
start(javafx.stage.Stage)
method- Waits for the application to finish, which happens when either of the following occur:
- the application calls
Platform.exit()
- the last window has been closed and the
implicitExit
attribute onPlatform
istrue
- Calls the stop() method
I start the Inversion of Control (IoC) container in init()
and stop it in stop()
. Now my Application
class has a reference to the IoC container and can supply the first controller with its dependencies.
As a matter of fact, I let the IoC framework manage the controllers. I set them to the loaded FXML using FXMLLoader.setController()
, instead of specifying them with fx:controller
.
Upvotes: 4
Reputation: 2687
You can pass a static reference to your application class before you call launch()
. Something like:
public class Frontend {
public Frontend(MBassador<EventBase> eventBus) {
AppGui.setEventBus(eventBus);
Application.launch(AppGui.class);
}
}
public class AppGui extends Application {
private static MBassador<EventBase> eventBus;
public static void setEventBus(MBassador<EventBase> eventBus) {
this.eventBus = eventBus;
}
private MBassador<EventBase> eventBus;
@Override
public void init() {
if (AppGui.eventBus == null) {
throw new IllegalStateException();
// or however you want to handle that state
} else {
this.eventBus = AppGui.eventBus;
AppGui.eventBus = null;
}
}
}
Whether you keep and use the static reference, or you copy the static reference to a local reference is up to you and the design of your application. If you expect to instantiate more than one copy of AppGui, you may need the local reference.
No idea if this is thread safe (probably not). The advice from @Nikos and @James_D is solid and preferred... but sometimes you just need a hack. :) YMMV
Upvotes: 1