Dagger 2 - two提供了提供相同接口的方法

时间:2016-10-10 08:13:01

标签: java android dependency-injection dagger-2 dagger

我想说:

public interface Shape  {}


public class Rectangle implements Shape {

}

public class Circle implements Shape {

}

我有 ApplicationModule ,需要为 Rec 提供实例:

@Module
public class ApplicationModule {
    private Shape rec;
    private Shape circle;

    public ApplicationModule() {
        rec = new Rectangle();
        circle= new Circle ();
    }

    @Provides
    public Shape provideRectangle() {
        return rec ;
    }

    @Provides
    public Shape provideCircle() {
        return circle;
    }
}

ApplicationComponent

@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
    Shape provideRectangle();
}

代码的方式 - 它不会编译。 错误说

  

错误:(33,20)错误:形状被多次绑定。

对我来说这是不可能的,因为组件正在尝试查找Shape实例,并且它找到了其中的两个,因此它不知道返回哪一个。 / p>

我的问题是 - 我该如何处理这个问题?

4 个答案:

答案 0 :(得分:31)

我最近在这篇文章中回答了这样的问题:

Dagger 2 : error while getting a multiple instances of same object with @Named

您需要在模块中使用@Named("someName"),如下所示:

@Module
public class ApplicationModule {
private Shape rec;
private Shape circle;

public ApplicationModule() {
    rec = new Rectangle();
    circle= new Circle ();
}

@Provides
 @Named("rect")
public Shape provideRectangle() {
    return rec ;
}

@Provides
 @Named("circle")
public Shape provideCircle() {
    return circle;
}

}

然后,无论你需要注射它们,只需写下

@Inject
@Named("rect")
 Shape objRect;

它很有趣,但你必须以不同的方式注入Kotlin:

@field:[Inject Named("rect")]
lateinit var objRect: Shape

答案 1 :(得分:12)

@Qualifier注释是区分具有相同类型的不同实例或注入请求的正确方法。主要用户指南页面有a whole section on them

@Qualifier @Retention(RUNTIME)
public interface Parallelogram {} /* name is up to you */

// In your Module:
@Provides @Parallelogram
public Shape provideRectangle() {
    return rec ;
}

// In your other injected types:
@Inject @Parallelogram Shape parallelogramShape;
// or
@Inject @Parallelogram Provider<Shape> parallelogramShapeProvider;

// In your Component:
@Parallelogram Shape provideRectangle();

除此之外:虽然我同意第11部分您不应该在注入类型中使用new,但如果需要,模块恰好是调用new的正确位置。除了添加限定符注释之外,我还说你的模块对我来说是正确的。

关于使用@Named与自定义限定符注释相比,

编辑

  • @Named是一个内置的@Qualifier注释,非常类似于我上面创建的注释。对于简单的情况,它工作得很好,但由于绑定只是一个字符串,因此您无法从IDE中获得有关检测有效密钥或自动完成密钥的帮助。
  • 与Named&#39的字符串参数一样,自定义限定符可以包含字符串,基元,枚举或类文字属性。对于枚举,IDE通常可以自动填充有效值。
  • @Named可以通过在组件方法上指定注释,以完全相同的方式从注释中访问自定义限定符,正如我上面的@Parallelogram所做的那样。

答案 2 :(得分:6)

我认为在new的构造函数中使用Module运算符并不是一个好主意。这将在初始化对象图形时(即,当您调用new ApplicationModule()时)创建每个提供的对象的实例,而不是在Dagger第一次需要对象时。在这种情况下(只有两个对象),它可以忽略不计,但在较大的项目中,这可能会导致应用程序启动时出现瓶颈。相反,我会遵循@ sector11的建议,并在@Provides带注释的方法中实例化你的对象。

至于提供两个相同类型的对象,@ Jeff和@Amir都是正确的。您可以使用提供的@Named()限定符,也可以创建自己的限定符,如下所示:

@Qualifier @Retention(RetentionPolicy.RUNTIME)
public @interface RectangleShape {}

@Qualifier @Retention(RetentionPolicy.RUNTIME)
public @interface CircleShape {}

然后你的ApplicationModule应该是这样的:

@Module
public class ApplicationModule {

    @Provides @RectangleShape // @Named("rectangle")
    public Shape provideRectangle() {
        return new Rectangle();
    }

    @Provides @CircleShape // @Named("circle")
    public Shape provideCircle() {
        return new Circle();
    }

}

有了这个,您可以将这些对象注入到您的类中:

@Inject @RectangleShape /* @Named("rectangle") */ public Shape mRectangle;
@Inject @CircleShape /* @Named("circle") */ public Shape mCircle;

如果您需要在没有Shape注释的情况下提供@Inject课程的实例,则可以在Component课程中执行此操作:

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

    void inject(MyApplication application);

    @RectangleShape // @Named("rectangle")
    Shape getRectangle();

    @CircleShape // @Named("circle")
    Shape getCircle();

}

这些方法将提供@Provides注释方法提供的每个类的相同实例。

答案 3 :(得分:2)

除了@Named和自定义限定符(在其他回复中显示)之外,您还可以使用带有 enum 参数的自定义限定符:

// Definition

@Qualifier
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface ShapeType {
  ShapeTypeEnum value(); /* default ShapeTypeEnum.RECTANGLE; */
}

public enum ShapeTypeEnum {
  RECTANGLE, CIRCLE
}

// Usage

@Provides @ShapeType(ShapeTypeEnum.RECTANGLE)
public Shape provideRectangle() {
    return new Rectangle();
}

@Inject @ShapeType(ShapeTypeEnum.RECTANGLE) Shape rectangle;

这是@Named(需要字符串键,容易出错且无法自动完成)和自定义限定符(每个实现需要一个文件)之间的混合。