【问题标题】:Can I use some kind of assisted Inject with Dagger?我可以使用 Dagger 的某种辅助 Inject 吗?
【发布时间】:2015-05-24 08:42:59
【问题描述】:

使用 Google Guice 或 Gin,我可以指定不受依赖注入框架控制的参数:

class SomeEditor {


  @Inject
  public SomeEditor(SomeClassA a, @Assisted("stage") SomeClassB b) {
  }

}

在创建SomeEditor 的实例时指定辅助参数stage

SomeClassA 的实例取自对象图,SomeClassB 的实例取自运行时的调用者。

在 Dagger 中有类似的方法吗?

【问题讨论】:

  • 你能说得更准确点吗?
  • SomeClassA 的实例取自对象图,SomeClassB 的实例取自运行时的调用者。

标签: java guice dagger gwt-gin dagger-2


【解决方案1】:

因为工厂是一种需要优化的单独类型的样板 (see mailing list discussion here),所以 Dagger 将其留给了姊妹项目 AutoFactory。这提供了 Guice 通过FactoryModuleBuilder 提供的“assisted injection”功能,但还有一些额外的好处:

  • 您可以继续将 AutoFactory 与 Guice 或 Dagger 或任何其他 JSR-330 依赖注入框架一起使用,因此即使您在它们之间切换也可以继续使用 AutoFactory。
  • 由于 AutoFactory 生成代码,您无需编写接口来表示构造函数:AutoFactory 将编写一个全新的类型供您编译。 (如果您愿意,或者要从 Guice 迁移,您也可以指定要实现的接口。)
  • 因为所有类型检查都是在编译时进行的,所以它会生成普通的旧 Java,它不会因反射而出现任何缓慢,并且可以很好地与调试器和优化器配合使用。这使得 Auto 库对 Android 开发特别有用。

示例,从 AutoFactory 的 README 中提取,它将在 @Inject 带注释的构造函数中生成带有 providedDepASomeClassFactory,在 create 方法中生成 depB

@AutoFactory
final class SomeClass {
  private final String providedDepA;
  private final String depB;

  SomeClass(@Provided @AQualifier String providedDepA, String depB) {
    this.providedDepA = providedDepA;
    this.depB = depB;
  }

  // …
}

【讨论】:

    【解决方案2】:

    是的,请查看这个 Square 项目:square/AssistedInject

    目前它还没有在 1.0 中。他们等到 Dagger 引入一个公共 API 来自动注册那些生成的 Module 类 - 请参阅 this issue。这样您就不必在 Dagger 代码中引用它们,就像在 README 的这个示例中一样:

    @AssistedModule
    @Module(includes = AssistedInject_PresenterModule.class)
    abstract class PresenterModule {}
    

    【讨论】:

      【解决方案3】:

      就像@xsveda 一样,我也写了一个关于这个in this other question 的答案,我也会在这里复制。


      今天,对于 Dagger 的辅助注射,您可能想要使用 AssistedInject。我在this blogpost 中写过它,但我会在此处添加一个完整的示例以使事情变得更容易。

      首先需要的是依赖项:

      compileOnly 'com.squareup.inject:assisted-inject-annotations-dagger2:0.4.0'
      kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.4.0'
      

      下面是它的样子:

      class ImageDownloader @AssistedInject constructor(
        private val httpClient: HttpClient,
        private val executorService: ExecutorService,
        @Assisted private val imageUrl: URL,
        @Assisted private val callback: ImageCallback
      ) {
      
        @AssistedInject.Factory
        interface Factory {
          fun create(imageUrl: URL, callback: ImageCallback): ImageDownloader
        }
      }
      

      首先,我们不是用@Inject 注释构造函数,而是用@AssistedInject 注释它。然后我们注释必须通过工厂的参数,这与 AutoFactory 所期望的相反。最后,我们需要一个带有 @AssistedInject.Factory 注释的内部工厂接口,它有一个接收辅助参数并返回我们感兴趣的实例的方法。

      很遗憾,我们这里还有一个额外的步骤:

      @AssistedModule
      @Module(includes = [AssistedInject_AssistedInjectModule::class])
      interface AssistedInjectModule
      

      我们不一定需要专门的模块,即使这是一个有效的选项。但是我们也可以将这些注释放在已经安装在组件中的另一个模块中。这里的好处是我们只需要这样做一次,之后任何工厂都会自动成为图表的一部分。

      有了它,你基本上可以像往常一样注入工厂并请求你的对象。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-25
        • 2019-05-04
        • 1970-01-01
        • 1970-01-01
        • 2011-09-16
        • 1970-01-01
        相关资源
        最近更新 更多