我正在尝试通过 Dagger 2 学习 DI 并将其应用到我们的产品中。注释的应用程序级别的东西@Singleton
非常简单(例如SharedPreferences
)。在考虑我们的架构时,有几个本质上是异步的依赖项,我想象它们的范围@ForSession
。
AccountManager
。在现有有效会话的情况下可以是同步的。如果没有现有会话,并且AccountManager
必须显示完整的登录流程,则可能是异步的。Endpoint
来满足依赖关系,以便我们的网络层知道在哪里可以找到 API。Service
。Service
仅当绑定完成 时才异步提供该组件。表示层应在收到这些项目的集合后进行门控。除了某种“正在加载”显示之外,如果没有上述任何一项,它就无能为力。
感觉这些依赖项适合 和 的用@ProducerModule
例@Produces
。我觉得我可以@Produces ListenableFuture<>
为每个依赖项提供方法,也许可以使用 aSettableFuture<>
作为实现。执行任何需要的工作,呼唤set()
未来,依赖性得到满足。
我感到不安的地方是《制作人指南》中的这句话。
正如上面的例子,生产者模块可以与普通模块无缝使用,但受到提供类型不能依赖于生产类型的限制。
对于“所有可用的东西的门演示”,我可以设想一个复合对象,可以@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);
}
}
Run Code Online (Sandbox Code Playgroud)
然后是组件:
@ForSession
@ProductionComponent(modules = SessionModule.class)
public interface SessionComponent {
ListenableFuture<CompositeSessionInfo> getCompsiteSessionInfoFuture();
}
Run Code Online (Sandbox Code Playgroud)
在我想要的地方我可以做类似的事情:
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);
}
});
Run Code Online (Sandbox Code Playgroud)
我对这部分的理解是否有偏差?顺便说一句:为什么要@Produces
声明这些方法static
?这是必需的吗?(编辑:static
肯定不是必需的,但我不确定除了不在Module
)。
编辑:
我决定创建一个概念验证项目,从实际项目中抽象出我的想法。一切都按照我的意愿进行,除了我无法获得@Inject
任何我的@Produce
项目,无论是最终结果“复合”数据还是中间结果。如果我在组件中公开 getter,我就可以获取它们,这就是我所做的。
我当前的计划是将这种@Producer
基于异步的东西放在一个单独的可注入模块中,然后将生成的依赖项输入到一个@Provides
样式模块中,该样式模块可以输入到其他地方,以便可以对它们进行@Inject
编辑。
编辑编辑:
更新了概念证明,以具有共同的前体依赖性,以更接近地模仿我的需求。仍然不能@Inject。我相信这与我所能得到的一样好。
好吧,既然看来我要单独行动,我会将我的最终结论作为我自己的答案发布,希望能帮助其他想要做类似事情的人。
我再次更新了我的概念验证项目。现在,一旦满足所有异步依赖项,新的单个复合依赖项就是一个实际的 @Module,@Produced
由新重命名的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;
}
Run Code Online (Sandbox Code Playgroud)
现在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
}
});
Run Code Online (Sandbox Code Playgroud)
一旦Future
成功,我就可以像人们所期望的那样获得依赖项和任何带注释的inject()
字段。
这样一来,我其实就可以拥有之后了。MainActivity
@Injected
@Inject
@Produce
没有我想要的那么干净,但仍然比没有 DI 好。现在,可以按任何顺序满足任意数量的异步依赖项(在任何时间范围内运行),并且一旦所有这些依赖项都准备好,就可以Future
设置单个依赖项,并SessionProvisionComponent
准备好将依赖项与这些@Produced
依赖项一起注入。
主要是快乐。
归档时间: |
|
查看次数: |
952 次 |
最近记录: |