简体   繁体   English

我可以在Dagger中使用某种辅助注射吗?

[英]Can I use some kind of assisted Inject with Dagger?

With Google Guice or Gin I can specify parameter with are not controlled by the dependency injection framework: 使用Google Guice或Gin,我可以指定不受依赖项注入框架控制的参数:

class SomeEditor {


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

}

The assisted parameter stage is specified at the time an instance of SomeEditor is created. 在创建SomeEditor的实例时指定辅助参数stage

The instance of SomeClassA is taken from the object graph and the instance of SomeClassB is taken from the caller at runtime. SomeClassA的实例是从对象图中获取的,而SomeClassB的实例是从运行时的调用者获取的。

Is there a similar way of doing this in Dagger? 在Dagger中有类似的方法吗?

Because factories are a separate type of boilerplate to optimize away ( see mailing list discussion here ), Dagger leaves it to a sister project, AutoFactory . 因为工厂是一种单独的样板,可以进行优化( 请参阅此处的邮件列表讨论 ),所以Dagger将其留给了姊妹项目AutoFactory This provides the " assisted injection " functionality Guice offers via FactoryModuleBuilder , but with some extra benefits: 这提供了Guice通过FactoryModuleBuilder提供的“ 辅助注入 ”功能,但具有一些额外的好处:

  • You can keep using AutoFactory with Guice or Dagger or any other JSR-330 dependency injection framework, so you can keep using AutoFactory even if you switch between them. 您可以继续将AutoFactory与Guice或Dagger或任何其他JSR-330依赖项注入框架一起使用,因此即使在它们之间进行切换,也可以继续使用AutoFactory。
  • Because AutoFactory generates code, you don't need to write an interface to represent the constructor: AutoFactory will write a brand new type for you to compile against. 因为AutoFactory会生成代码,所以您无需编写用于表示构造函数的接口:AutoFactory将编写一个全新的类型供您进行编译。 (You can also specify an interface to implement, if you'd prefer, or if you're migrating from Guice.) (如果愿意,或者从Guice迁移,也可以指定要实现的接口。)
  • Because all the type inspection happens at compile-time, it produces plain old Java, which doesn't have any slowness due to reflection and which works well with debuggers and optimizers. 因为所有类型检查都是在编译时进行的,所以它会生成普通的旧Java,它不会因反射而变慢,并且可以与调试器和优化器一起很好地工作。 This makes the Auto library particularly useful for Android development. 这使得Auto库对于Android开发特别有用。

Example, pulled from AutoFactory's README, which will produce a SomeClassFactory with providedDepA in an @Inject -annotated constructor and depB in a create method: 例如,从AutoFactory的README中提取的,它将在@Inject depB构造函数中providedDepA带有depBSomeClassFactory ,并在create方法中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;
  }

  // …
}

Yes, please check this Square project: square/AssistedInject 是的,请检查以下Square项目: square / AssistedInject

Currently it is not in 1.0 yet for purpose. 目前还没有在1.0中使用。 They wait until Dagger will introduce a public API for registering those generated Module classes automatically - see this issue . 他们等到Dagger引入一个公共API来自动注册那些生成的Module类-请参见此问题 With that you won't have to reference them in your Dagger code as in this example from README : 这样,您就不必在README中的本示例中在Dagger代码中引用它们:

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

Just like @xsveda, I also wrote an answer about this in this other question , which I'll also reproduce here. 就像@xsveda一样,我在另一个问题中也写了一个答案,我也会在这里重现。


Today, for assisted injection with Dagger you probably want to use AssistedInject . 今天,对于Dagger的辅助注入,您可能要使用AssistedInject I wrote about it in this blogpost , but I'll add a full example here to make things easier. 我在此博客文章中对此进行了介绍 ,但在我将添加一个完整的示例以简化操作。

First thing you need are the dependencies: 您需要的第一件事是依赖项:

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

Then here's how it can look like: 然后是这样的:

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
  }
}

First thing is that instead of annotating the constructor with @Inject , we annotate it with @AssistedInject . 首先,我们不是使用@Inject注释构造函数,而是使用@AssistedInject对其进行@AssistedInject Then we annotate the parameters that will have to go through the factory, which is the opposite of what AutoFactory expects. 然后,我们注释必须通过工厂的参数,这与AutoFactory期望的相反。 Finally, we need an inner factory interface annotated with @AssistedInject.Factory that has a single method that receives the assisted parameters and returns the instance we're interested in. 最后,我们需要一个内部工厂接口,该接口带有@AssistedInject.Factory注释,该接口具有单个方法,该方法接收辅助参数并返回我们感兴趣的实例。

Unfortunately, we still have an extra step here: 不幸的是,我们在这里还有一个额外的步骤:

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

We don't necessarily need a dedicated module for it, even though that's a valid option. 即使这是一个有效的选择,我们也不一定需要专用的模块。 But we can also have those annotations in another module that is already installed in the component. 但是我们也可以在组件中已安装的另一个模块中具有这些注释。 The nice thing here is that we only need to do it once, and after that any factory will automatically become part of the graph. 这里的好处是我们只需要执行一次,然后任何工厂都将自动成为图形的一部分。

With that, you can basically inject the factory and ask for your object as you'd normally do. 这样,您就可以像通常那样注入工厂并索要对象了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM