为什么Dagger 2要求我使用@Provides而不是@Binds?

3

我现在正在研究Dagger 2(Java),但是一开始就遇到了问题。不幸的是,我在Dagger 2文档或Stackoverflow上还没有找到任何关于此问题的信息,所以如果您知道一些资源,我将非常感激。

我在这个存储库中准备了一个最小的示例来解释我的问题:https://github.com/stackoverflow-samples/dagger2-dependency-cycle

所以我们有一个 Application 类应该被构建

public class Application {

    @Inject
    public Application(SomeDependency one) {

    }

    public static void main(String[] args) {
        DaggerApplicationComponent.create().build();
    }
}

...带有虚拟依赖

public class SomeDependency {

    @Inject
    public SomeDependency() {

    }
}

当然,Dagger类/接口也是必不可少的... ..一个组件接口:

@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
    Application build();
}

...和一个模块:

@Module
abstract class ApplicationModule {
    @Provides
    static SomeDependency provideDepdendencyOne() {
        return new SomeDependency();
    }
}

我不明白的是为什么Dagger强制要求我使用@Provides注解注册SomeDependency,而不允许我通过@Binds进行注册。
@Binds 
abstract SomeDependency bindDepdendencyOne(SomeDependency one);

每当我将代码从@Provides更改为@Binds时,它会给我以下错误:
[Dagger/DependencyCycle] Found a dependency cycle:
      io.github.codejanovic.dagger2.example.SomeDependency is injected at
          io.github.codejanovic.dagger2.example.ApplicationModule.bindDepdendencyOne(one)
      io.github.codejanovic.dagger2.example.SomeDependency is injected at
          io.github.codejanovic.dagger2.example.Application(one)
      io.github.codejanovic.dagger2.example.Application is provided at
          io.github.codejanovic.dagger2.example.ApplicationComponent.build()

我完全无法理解为什么不能@Bind一个实现。我忽略了什么吗?

提前致谢。

2个回答

6
你错误地认为你需要@Binds@Provides。你应该使用构造函数注入,而不是模式,而是Dagger生成代码的方式。
你已经用@Inject注释了构造函数,因此Dagger知道这个类以及如何创建它。没有其他事情需要做。
public class SomeDependency {

    @Inject
    public SomeDependency() {

    }
}

您的这个简单用例不需要任何@Provides@Binds甚至@Module。因为两个构造函数都使用了@Inject注释,所以您的示例应该可以直接工作。

@Component
public interface ApplicationComponent {
    Application build();
}

如果您需要指定范围,可以在类上添加它。
@Provides 应该用于无法使用构造函数注入的代码,或者需要额外设置的代码。当然,您可以手动创建所有对象(就像在示例中所做的那样),但这没有真正的好处,并且只会产生许多可以避免的样板文件。 @Binds 用于将实现绑定到接口。最理想的情况是对实现也使用构造函数注入,但您也可以将其添加到组件构建器 (@BindsInstance) 或在 @Provides 注释方法中创建它。
@Binds MyInterface bindMyImplementation(MyImplementation implementation);

1
如果您的类被标记为@Inject构造函数:
public class SomeDependency {

    @Inject // <----
    public SomeDependency() {

    }
}

如果您需要将对象作为接口的实现或与其具体类型不同的不同类型进行“绑定”,则只需要使用@Binds(或@Provides)。

此外,如果您的对象具有@Inject构造函数,则无需在模块中实例化它,因为Dagger已经知道如何实例化它。

因此,要修复您的代码,您只需要执行以下操作:

// @Module
// abstract class ApplicationModule {
//     @Provides
//     static SomeDependency provideDepdendencyOne() {
//         return new SomeDependency();
//     }
// }

解决了。

哦,我的天啊...这就是我所错过的,谢谢大家!由于我用的是Guice,我以为声明是必需的! - codejanovic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接