Seb*_*n S 9 java dependency-injection javafx dagger-2
JavaFX 本身有一些 DI 方法来允许在 XML 描述的 UI 和控制器之间进行绑定:
<Pane fx:controller="foo.bar.MyController">
<children>
<Label fx:id="myLabel" furtherAttribute="..." />
</children>
</Pane>
Run Code Online (Sandbox Code Playgroud)
Java 端看起来像这样:
public class MyController implements Initializable {
@FXML private Label myLabel;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
// FXML-fields have been injected at this point of time:
myLabel.setText("Hello world!");
}
}
Run Code Online (Sandbox Code Playgroud)
为此,我不能只创建 MyController 的实例。相反,我必须要求 JavaFX 为我做一些事情:
FXMLLoader loader = new FXMLLoader(MyApp.class.getResource("/fxml/myFxmlFile.fxml"), rb);
loader.load();
MyController ctrl = (MyController) loader.getController();
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好
但是,如果我想使用 Dagger 2 将一些非 FXML 依赖项注入到这个控制器类的构造函数中,我有一个问题,因为我无法控制实例化过程,如果我使用 JavaFX。
public class MyController implements Initializable {
@FXML private Label myLabel;
/*
How do I make this work?
private final SomeService myService;
@Inject
public MyController(SomeService myService) {
this.myService = myService;
}
*/
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
// FXML-fields have been injected at this point of time:
myLabel.setText("Hello world!");
}
}
Run Code Online (Sandbox Code Playgroud)
有一个 API 看起来很有前途:loader.setControllerFactory(...);也许这是一个很好的起点。但是我对这些库没有足够的经验来知道如何解决这个问题。
感谢@Sebastian_S 的映射多重绑定机制提示,我已经成功地使用将每个控制器映射到其类来进行自动控制器绑定Map<Class<?>, Provider<Object>>。
在模块中,将所有控制器收集到名为“Controllers”的映射中,并具有相应的类键
@Module
public class MyModule {
// ********************** CONTROLLERS **********************
@Provides
@IntoMap
@Named("Controllers")
@ClassKey(FirstController.class)
static Object provideFirstController(DepA depA, DepB depB) {
return new FirstController(depA, depB);
}
@Provides
@IntoMap
@Named("Controllers")
@ClassKey(SecondController.class)
static Object provideSecondController(DepA depA, DepC depC) {
return new SecondController(depA, depC);
}
}
Run Code Online (Sandbox Code Playgroud)
然后在 Component 中,我们可以使用它的名称来获取这个 Map 的实例。该映射的值类型应该是Provider<Object>因为我们希望每次需要时都获得一个新的控制器实例FXMLLoader。
@Singleton
@Component(modules = MyModule.class)
public interface MyDiContainer {
// ********************** CONTROLLERS **********************
@Named("Controllers")
Map<Class<?>, Provider<Object>> getControllers();
}
Run Code Online (Sandbox Code Playgroud)
最后,在 FXML 加载代码中,您应该设置新的 ControllerFactory
MyDiContainer myDiContainer = DaggerMyDiContainer.create()
Map<Class<?>, Provider<Object>> controllers = myDiContainer.getControllers();
FXMLLoader loader = new FXMLLoader();
loader.setControllerFactory(type -> controllers.get(type).get());
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3498 次 |
| 最近记录: |