web-dev-qa-db-ja.com

ダガー2-2つは同じインターフェースを提供するメソッドを提供します

私が持っていると言うことができます:

public interface Shape  {}


public class Rectangle implements Shape {

}

public class Circle implements Shape {

}

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

およびApplicationComponent

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

そのままのコードでは-コンパイルされません。言っているエラー

エラー:(33、20)エラー:図形が複数回バインドされています。

コンポーネントがShapeインスタンスを見つけようとしていて、そのうちの2つを見つけているので、どちらを返すかわからないので、これができないことは理にかなっています。

私の質問は-この問題をどのように処理できますか?

29
Ofek Agmon

私は最近、この投稿でこのような質問への回答を投稿します:

ダガー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;
}

}

その後、あなたがそれらを注入する必要があるところはどこでも書くだけ

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

その面白いが、Kotlinで別の方法で注入する必要があります。

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

@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();

余談:injected型ではnewを使用すべきではないというセクター11に同意しますが、new if必要です。修飾子の注釈を追加することは別として、あなたのモジュールは私にぴったりだと思います。


[〜#〜] edit [〜#〜]カスタム修飾子アノテーションと比較した@Namedの使用に関して:

  • @Namedは組み​​込みの@Qualifierアノテーションで、上記で作成したものとよく似ています。単純な場合、それはうまく機能しますが、バインディングは単なる文字列であるため、有効なキーの検出またはキーの自動補完においてIDEからあまり助けを得ることはありません。
  • Namedの文字列パラメーターと同様に、カスタム修飾子には文字列、プリミティブ、列挙、またはクラスリテラルプロパティを含めることができます。列挙型の場合、IDEは多くの場合、有効な値を自動補完できます。
  • @Namedおよびカスタム修飾子は、上記の@Parallelogramで行ったように、コンポーネントメソッドでアノテーションを指定することにより、まったく同じ方法でアノテーションからアクセスできます。
12
Jeff Bowman

newのコンストラクター内でModule演算子を使用することはお勧めできません。これにより、Daggerがオブジェクトを初めて必要とするときではなく、オブジェクトグラフの初期化時(つまり、new ApplicationModule()を呼び出したとき)に、提供された各オブジェクトのインスタンスが作成されます。この場合(オブジェクトが2つだけの場合)、それは無視できますが、大規模なプロジェクトでは、アプリケーションの起動時にボトルネックを引き起こす可能性があります。代わりに、@ sector11による提案に従い、_@Provides_アノテーション付きメソッドでオブジェクトをインスタンス化します。

同じタイプの2つのオブジェクトを提供する場合、@ 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;
_

_@Inject_アノテーションなしでShapeクラスのインスタンスを提供する必要がある場合は、Componentクラスで提供できます。

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

    void inject(MyApplication application);

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

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

}
_

これらのメソッドは、_@Provides_アノテーション付きメソッドによって提供される各クラスの同じインスタンスを提供します。

6
Bryan

に加えて @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(エラーが発生しやすく、オートコンプリートできないStringキーが必要です)およびカスタム修飾子(実装ごとにファイルが必要です)。

2