可能我错过了一些东西,但我正在努力寻找一个解决方案,如何将依赖项(例如事件总线的实例和一些服务接口)传递到我的 javafx 应用程序。
我有一个 UI-Init 类,它只不过是启动应用程序并接收 UI 的一些依赖项(如 eventBus):
public class Frontend {
public Frontend(MBassador<EventBase> eventBus) {
Application.launch(AppGui.class);
}
我的 AppGui 类扩展了 Application 并加载 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();
}
}
现在,我如何将我的 eventBus 和其他服务接口传递给这个控制器?我读过有关使用 guice(JavaFX 控制器如何访问其他服务?)或 afterburner.fx 等 DI 框架的信息来使用它。但即使我在应用程序的其余部分使用 guice,我还是需要将 Injector 实例传递给 JavaFX 应用程序?.
但是Application.launch(AppGui.class);是静态的,并在 javafx 线程上内部创建一个 AppGui 实例,我无法访问该实例。那么如何在不使用静态变量的情况下将依赖项注入到我的 AppGui 对象中呢?
这就是我所做的:
Application
类有几个生命周期回调,init()
和stop()
。
来自 Javadoc:
public void init() throws java.lang.Exception
应用程序初始化方法。在加载并构造 Application 类后立即调用此方法。应用程序可以重写此方法以在应用程序实际启动之前执行初始化。
public void stop() throws java.lang.Exception
当应用程序应该停止时调用此方法,并提供一个方便的地方来准备应用程序退出和销毁资源。
同样来自 Javadocs,生命周期:
- 构造指定
类的实例Application
- 调用
方法init()
- 调用
方法start(javafx.stage.Stage)
- 等待应用程序完成,当发生以下任一情况时会发生这种情况:
- 应用程序调用
Platform.exit()
- 最后一个窗口已关闭,
上的implicitExit
属性为Platform
true
- 调用 stop() 方法
我在 init()
中启动
控制反转 (IoC)容器,并在
stop()
中停止它。现在我的 Application
类有了对 IoC 容器的引用,并且可以为第一个控制器提供其依赖项。
事实上,我让IoC框架来管理控制器。我使用
FXMLLoader.setController()
将它们设置为加载的 FXML,而不是使用 fx:controller
指定它们。
您可以在调用
launch()
之前传递对应用程序类的静态引用。比如:
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;
}
}
}
是否保留并使用静态引用,或者将静态引用复制到本地引用取决于您和应用程序的设计。如果您希望实例化多个 AppGui 副本,则可能需要本地引用。
不知道这是否是线程安全的(可能不是)。 @Nikos 和 @James_D 的建议是可靠且首选的......但有时您只需要一个技巧。 :) YMMV