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

Ofe*_*mon 31 java android dependency-injection dagger dagger-2

让我说我有:

public interface Shape  {}


public class Rectangle implements Shape {

}

public class Circle implements Shape {

}
Run Code Online (Sandbox Code Playgroud)

我有一个ApplicationModule,它需要为RecCircle提供实例:

@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;
    }
}
Run Code Online (Sandbox Code Playgroud)

ApplicationComponent:

@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
    Shape provideRectangle();
}
Run Code Online (Sandbox Code Playgroud)

使用代码的方式 - 它将无法编译.错误说

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

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

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

Ami*_*ati 43

我最近在这篇文章中发布了这样一个问题的答案:

Dagger 2:使用@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;
}
Run Code Online (Sandbox Code Playgroud)

}

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

@Inject
@Named("rect")
 Shape objRect;
Run Code Online (Sandbox Code Playgroud)


Jef*_*ica 13

@Qualifier注释是区分具有相同类型的不同实例或注入请求的正确方法.主用户指南页面上有完整的部分.

@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();
Run Code Online (Sandbox Code Playgroud)

除此之外:虽然我同意您不应该new注入类型中使用sector11,但new如果需要,模块就是正确的调用位置.除了添加限定符注释之外,我会说你的模块看起来恰到好处.


关于使用@Named与自定义限定符注释相比的编辑:

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


Bry*_*yan 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 {}
Run Code Online (Sandbox Code Playgroud)

然后你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();
    }

}
Run Code Online (Sandbox Code Playgroud)

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

@Inject @RectangleShape /* @Named("rectangle") */ public Shape mRectangle;
@Inject @CircleShape /* @Named("circle") */ public Shape mCircle;
Run Code Online (Sandbox Code Playgroud)

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

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

    void inject(MyApplication application);

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

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

}
Run Code Online (Sandbox Code Playgroud)

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