@Produces 之后的 @Injects?

Bri*_*uis 5 android dagger-2

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

  • 我们的身份验证令牌/帐户信息,从 Android 获取AccountManager。在现有有效会话的情况下可以是同步的。如果没有现有会话,并且AccountManager必须显示完整的登录流程,则可能是异步的。
  • 一旦我们有了有效的会话令牌和会话信息:
    • 提供一个Endpoint来满足依赖关系,以便我们的网络层知道在哪里可以找到 API。
    • 从网络 API 获取我们的“用户”信息。
    • 从网络 API(或本地缓存)中提取额外的支持信息。
    • 从网络 API(或本地缓存)中提取本地化的后端字符串。
    • 让依赖于绑定的组件运行起来ServiceService仅当绑定完成 时才异步提供该组件。

表示层应在收到这些项目的集合后进行门控。除了某种“正在加载”显示之外,如果没有上述任何一项,它就无能为力。

感觉这些依赖项适合 和 的用@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。我相信这与我所能得到的一样好。

Bri*_*uis 1

好吧,既然看来我要单独行动,我会将我的最终结论作为我自己的答案发布,希望能帮助其他想要做类似事情的人。

我再次更新了我的概念验证项目。现在,一旦满足所有异步依赖项,新的单个复合依赖项就是一个实际的 @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依赖项一起注入。

主要是快乐。