今天我将 Guice 添加到我的 Java FX 应用程序中。主要目标是用注入(inject)替换我的单例并打破依赖关系。 到目前为止,一切正常,这是我必须启动新场景的代码:
public class App extends Application{
public static void main(String[] args){
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
final String LANGUAGE_BUNDLE = "myBundlePath";
final String FXML = "myFXMLPath";
try {
ResourceBundle resourceBundle = ResourceBundle.getBundle(LANGUAGE_BUNDLE, Locale.GERMAN, this.getClass().getClassLoader());
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(FXML), resourceBundle, new JavaFXBuilderFactory(), getGuiceControllerFactory());
primaryStage.setScene(new Scene(fxmlLoader.load()));
primaryStage.show();
}catch (IOException ex) {
ex.printStackTrace();
}
}
private Callback<Class<?>, Object> getGuiceControllerFactory(){
Injector injector = Guice.createInjector(new GuiceModule());
return new Callback<Class<?>, Object>() {
@Override
public Object call(Class<?> clazz) {
return injector.getInstance(clazz);
}
};
}
}
我的 Guice 模块如下所示:
public class GuiceModule extends AbstractModule {
@Override
protected void configure() {
bind(ITester.class).to(Tester.class);
bind(ISecondTest.class).to(SecondTest.class);
}
}
请注意,我替换了资源包和 fxml 文件的路径,因为它们会泄露我的身份。但是加载并且一切正常,所以这应该不是问题;)
现在的问题是,我想通过在不同 View 中单击按钮来实例化一个新 View 。第二个 View 应显示 View 1 中数据的更详细版本。 我需要传递给第二个 View 的所有内容都是整数(或 int),但我完全不知道如何做到这一点。
我有标准的 FX 设置:
View.fxml (with a reference to the ViewController)
ViewController.java
Model.java
ViewModel.java
然后,ViewController
绑定(bind)到 ViewModel
提供的属性。
我需要 int 来选择正确的模型。
我能找到的所有内容都是关于注释@Named
,但据我所知,这无法用于注入(inject)动态数据。
你能给我一个提示,我想做的事情叫什么吗? 或者长话短说:如何在第二个 ViewController 中注入(inject)由不同 View 选择的变量,并将其余部分保留在标准 FX 方式中?
感谢任何帮助,并提前致谢!
问候,克里斯蒂安
最佳答案
经过一番尝试,我似乎自己找到了解决方案! 然而,我正在做的事情“感觉”很丑,所以我想得到一些确认;)
首先是理论:Guice 支持“AssistedInject”。这是当类不能由默认构造函数构造时。为了能够使用 AssistedInject,您必须下载扩展(我从 maven repository 下载了 jar)。
AssistedInject 为您所做的是,它允许您指定一个为您构建变量的工厂。这就是我所做的:
首先,为稍后要使用的类创建一个接口(interface),在我的例子中:
public interface IViewController {
}
其次,为工厂创建一个接口(interface)。重要提示:您不必实现工厂
public interface IControllerFactory {
ViewController create(@Assisted int myInt);
}
第三,将带有相应参数的构造函数添加到您稍后要实例化的类中,并让它实现您创建的接口(interface),如下所示:
public class ViewController implements IViewController{
@AssistedInject
public ViewController(@Assisted int i){
final String LANGUAGE_BUNDLE = "languageBundle";
final String FXML = "View.fxml";
try{
ResourceBundle resourceBundle = ResourceBundle.getBundle(LANGUAGE_BUNDLE, Locale.GERMAN, this.getClass().getClassLoader());
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(FXML), resourceBundle, new JavaFXBuilderFactory());
fxmlLoader.setController(this);
Stage second = new Stage();
second.setScene(new Scene(fxmlLoader.load()));
second.show();
}catch (IOException e){
e.printStackTrace();
}
System.out.println("ViewController constructor called with: " + i);
}
以下几点需要注意:
- 方法的注释“@AssistedInject”
- 我们要从外部提供的参数的注释“@Assisted”
- 我们手动设置加载器的 Controller (使用 fxmlLoader.setController(this);)
- 我必须删除 fxml 文件中的 Controller 配置,因此 fxml 中没有“fx:controller”!
接下来,我们需要将一个变量添加到要实例化另一个类的类中:
@Inject
IControllerFactory controllerFactory;
我们可以在类中使用它,如下所示:
controllerFactory.create(3)
注意:我们将方法称为“create”,但我们从未在 ViewController 类中实现过该方法! Guice 知道它必须调用构造函数 - magic
最后一步,我们需要在 GuiceModule 中添加与上下文的连接,如下所示:
@Override
protected void configure(){
install(new FactoryModuleBuilder()
.implement(IPagingDirectoryViewController.class, PagingDirectoryViewController.class)
.build(IPagingDirectoryControllerFactory.class));
}
注意我收到错误:无法解析方法'implement java.lang.Class<"The interface class">, java.lang.Class<"The Implementing class">'。这是因为我忘记让我的 Controller 类实现该接口(interface)。
好的,这就是我的工作原理。 然而,正如我所说,我会很高兴听到一些意见!
问候,克里斯蒂安
关于java - 使用 Guice 将数据注入(inject) JavaFX ViewController,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36165151/