@Produces 之后@Injects?

@Injects after @Produces?

我正在尝试通过 Dagger 2 学习 DI 并将其应用到我们的产品中。用 @Singleton 注释的应用程序级别的东西非常简单(例如 SharedPreferences)。在考虑我们的架构时,有几个本质上是异步的依赖项,我想象它们的范围在 @ForSession 范围内。

表示层应在收到这些项目的集合时进行控制。除了某种 "loading" 显示,如果没有上述任何一项,它就无能为力了。

感觉这些依赖项适合 @ProducerModule@Produces 的用例。我觉得我可以为这些依赖项中的每一个提供 @Produces ListenableFuture<> 方法,也许 SettableFuture<> 作为实现。执行任何需要的工作,在那个未来调用 set(),满足依赖性。

我对 Producers guide.

中的这句话感到不安

As in the above example, producer modules can be used seamlessly with ordinary modules, subject to the restriction that provided types cannot depend on produced types.

对于 "gate presentation on everything being available" 我可以设想一个复合对象,它可以得到 @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 我的任何 @Produced 项目,最终结果 "composite" 数据或中间结果。如果我在组件中公开一个 getter,我就可以获得它们,这就是我所做的。

我目前的计划是将这个基于 @Producer 的异步内容放在一个单独的可注入模块中,然后将生成的依赖项输入到一个 @Provides 风格的模块中,该模块在其他地方提供,以便它们可以成为 @Injected.

编辑编辑:

更新了概念证明,使其具有共同的前体依赖性,从而更接近地模仿我的需求。仍然不能@Inject。我相信这和我得到的一样好。

好吧,看来我要单干了,我会 post 我的最终结论作为我自己的答案,希望能帮助其他想做类似事情的人。

我又更新了一次proof of concept project。现在,一旦满足所有异步依赖项,新的单一复合依赖项 是一个实际的 @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;
}

现在在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 和依赖项。 这样,我在@Produce之后居然可以有@Inject了。

没有我想要的那么干净,但仍然比没有 DI 好。现在,可以以任何顺序满足任意数量的异步依赖项,在任何时间范围内运行,并且一旦所有这些都准备就绪,就会设置一个 Future 并准备好 SessionProvisionComponent 来注入依赖项 @Produced依赖关系。

很开心。