我试图通过Dagger 2学习DI并将其应用到我们的产品中。使用@Singleton
注释的应用程序级别的内容非常简单(例如SharedPreferences
)。在考虑我们的体系结构时,有几个本质上是异步的依赖项,我想象的是@ForSession
作用域范围。
AccountManager
获取。在现有的有效会话的情况下可以是同步的。如果没有现有会话且AccountManager
必须显示完整的登录流程,则可以是异步的。Endpoint
以实现依赖关系,以便我们的网络层知道在哪里找到API。Service
的组件。仅在绑定的Service
绑定完成时异步提供该组件。 表单层应该在收到这些项目的集合时进行门控。除了某种" loading"显示,如果没有以上任何一项,它就无法做到。
感觉这些依赖项符合@ProducerModule
和@Produces
的用例。我觉得我可以为每个依赖项都有@Produces ListenableFuture<>
个方法,可能有一个SettableFuture<>
作为实现。执行所需的任何工作,在未来调用set()
,满足依赖性。
我感到厌倦的是Producers guide中的引用。
如上例所示,生产者模块可以与普通模块无缝地使用,但受限于提供的类型不能依赖于生成的类型。
关于所有可用的&#34;门演示&#34;我可以设想一个复合对象,它可以通过未解开的@Inject
未来获得T
。但这是否合法?
这是我最接近的,但它明确地调用了复合的构造函数,而不是注入它。有没有办法做到这个更清洁?
@ProducerModule
public class SessionModule {
@Produces
@ForSession
static ListenableFuture<User> produceSignedInUser(SessionManager sessionManager) {
return sessionManager.getSignedInUserFuture();
}
@Produces
@ForSession
static ListenableFuture<BoundService> produceBoundService(SessionManager sessionManager) {
return sessionManager.getBoundServiceFuture();
}
@Produces
@ForSession
static CompositeSessionInfo produceComposite(User user, BoundService service) {
return new CompositeSessionInfo(user, service);
}
}
然后是组件:
@ForSession
@ProductionComponent(modules = SessionModule.class)
public interface SessionComponent {
ListenableFuture<CompositeSessionInfo> getCompsiteSessionInfoFuture();
}
在某个我想要登机的地方我可以做类似的事情:
SessionComponent component = Dagger_SessionComponent.builder()
.executor(executor)
.build();
Futures.addCallback(component.getCompsiteSessionInfoFuture(),
new FutureCallback<CompositeSessionInfo> {
public void onSuccess(CompositeSessionInfo result) {
releaseTheHounds(result);
}
public void onFailure(Throwable t) {
reportError(t);
}
});
我对这一部分的理解是否有所帮助?除此之外:为什么@Produces
方法被宣布为static
?这需要吗? (编辑:static
确定不是必需的,但除了在Module
中没有实例字段外,我不确定其意图是什么。
修改
我决定创建一个proof of concept project来从我的实际项目中抽象出我的想法。一切正常,因为我喜欢除了,我无法@Inject
任何@Produce
d项,无论是最终结果还是#34;复合& #34;数据或中间结果。如果我在组件中暴露一个吸气剂,我可以得到它们,这就是我所做的。
我目前的计划是在一个单独的可注入模块中关闭这个基于@Producer
的异步函数,然后将结果依赖项送入@Provides
样式模块,该模块将在其他地方提供,以便它们可以{ {1}}编
编辑编辑:
更新了概念证明,使其具有共同的前兆依赖性,以更接近地模仿我的需求。仍然不能@Inject。我相信这和我一样好。
答案 0 :(得分:1)
好吧,因为看起来我单打独斗,我会将我的最终结论作为我自己的答案发布,希望能帮助其他想要做类似事情的人。
我再次更新了proof of concept project。现在,一旦满足所有异步依赖项,新的单一复合依赖项就是新重命名的@Produced
的实际@Module ,SessionProductionComponent
,那么该模块将被注册为组件称为SessionProvisionComponent
。此组件是标准@Component
,其@Provide
方法通过标准@Inject
机制提供依赖关系。
@Produces
@ForSession
public SessionProvisionModule produceSessionProvisionModule(Application app, SomeAsyncDependency someAsyncDependency, AnotherAsyncDependency anotherAsyncDependency) {
SessionProvisionModule module = new SessionProvisionModule(someAsyncDependency, anotherAsyncDependency);
((App) app).createSessionProvisionComponent(module);
return module;
}
现在在MainActivity
,当我需要获取会话信息时,它看起来是这样的:
App app = (App) getApplication();
sessionProductionComponent = app.getSessionProductionComponent();
if (app.getSessionProductionComponent() == null) {
sessionProductionComponent = app.createSessionProductionComponent(new SessionProductionModule());
}
Futures.addCallback(sessionProductionComponent.getSessionProvisionModuleFuture(),
new FutureCallback<SessionProvisionModule>() {
@Override
public void onSuccess(SessionProvisionModule result) {
app.getSessionProvisionComponent().inject(MainActivity.this);
}
@Override
public void onFailure(Throwable t) {
// handle failure
}
});
Future
成功后,我可以inject()
MainActivity
,任何带注释的字段都可以获得具有依赖关系的@Injected
。
通过这种方式,@Inject
之后我实际上可以@Produce
。
不像我想的那么干净,但仍然比没有DI更好。现在可以按任何顺序满足任何数量的异步依赖关系,无论何时都可以满足,并且一旦所有异步依赖关系都准备就绪,就会设置一个Future
并准备SessionProvisionComponent
来注入与@Produced
的依赖关系{ {1}}依赖项。
非常高兴。