2015-10-07 9 views
5

Ich entwickle Android App mit Dagger2.0.Wie würde die @Inject-Annotation wissen, welche konkrete Klasse unter derselben Schnittstelle instanziiert werden soll?

Ich bin verwirrt mit @Inject Annotation. Wenn ich zwei konkrete Klassen habe, die die gleiche Schnittstelle implementieren, und es gibt andere Klasse, die es verwendet, injiziere ich diese konkrete Klasse in den Client mit @Inject, So wie @Inject Annotation entscheiden kann, welche konkrete Klasse zu instanziieren.

Beispiel:

Ich habe eine Schnittstelle.

Product.java

public interface Product {} 

Es gibt insgesamt zwei konkrete Klassen ProductOne und ProductTwo.

ProductOne.class

public class ProductOne implements Product{ 

@Inject 
public ProductOne() {} 

} 

Verpackungsklasse ist der Kunde.

Packaging.java

public class Packaging{ 

@Inject 
public Packaging(Product product){} 

} 

Bis zu diesem Moment meiner Paket-Klasse verwendet Instanz ProductOne Klasse.

Verwirrung:

Wenn ich eine andere konkrete Klasse ProductTwo mit @Inject Anmerkung.

public class ProductTwo implements Product { 

@Inject 
public ProductTwo() {} 

} 

Jetzt in meiner Verpackung Klasse möchte ich Instanz ProductTwo Klasse verwenden, so dass diese @Inject Anmerkung in diesem Moment arbeiten?

+0

Überprüfen Sie @Inject Annotation Implementierung von Java und Ihre Verwirrung wird abgesehen von Gewinn Hölle des Wissens gelöscht werden !!! – hagrawal

+0

Ich glaube nicht, dass das funktioniert. Hast du es versucht? Gibt es einen Code, der '' ein 'Produkt' liefert? Weil das '@ Inject' dem Dolch nur sagt, wo andere Dinge injiziert werden sollen. Aber es sagt Dolch nicht, es an anderen Orten zu verwenden. – zapl

+0

@zapl für den ersten Fall nur mit einer konkreten Klasse habe ich es versucht und es hat funktioniert. Aber für zwei konkrete Klasse habe ich es nicht ausprobiert. – vsvankhede

Antwort

3

Ich gehe davon aus, dass Sie weder Module noch Komponenten erwähnen, mit denen Sie nicht vertraut sind und wie sie zusammenarbeiten.

Ihr Beispiel funktioniert nicht, da Dagger 2 nicht weiß, dass zur Erstellung eines Produkts eine der Klassen ProductOne oder ProductTwo verwendet werden muss. Auch wenn Dolch 2 sie verarbeiten wird (weil sie beide mit @Inject markiert wurden), wird es nicht automatisch davon ausgehen, dass sie nur dort eingesetzt werden, wo sie das Produkt implementieren. Der Grund dafür ist, dass es nicht wissen würde, welches zu verwenden ist, wenn es mehr als eins gibt, wie in diesem Fall.

Sie müssen also eine Bindung von ProductOne oder ProductTwo mit der Schnittstelle Produkt erstellen. Sie tun dies durch ein Modul.

@Module 
public class ProductOneModule { 
    @Provides Product provideProduct(ProductOne productOne) { 
    return productOne; 
    } 
} 

Ein Modul bietet nur eine Reihe von wiederverwendbaren Bindungen. Sie werden nicht wirklich verwendet (oder validiert), wenn sie nicht von einer Komponente verwendet werden. Eine Komponente kapselt all diese Informationen und verwaltet deren Erstellung. Dabei werden Module und ihre Bindungen und Factories verwendet, die für Klassen mit @Inject-Konstruktoren erstellt wurden.

Wenn Sie eine Komponente wie diese erstellen, wird Dolch 2 fehlschlagen, da es, wie oben erwähnt, nicht weiß, wie ein Produkt hergestellt wird.

@Component 
public interface PackagerOneComponent { 
    Packager packager(); 
} 

Der Fehler in etwa so sein wird:

 
Product cannot be provided without an @Provides-annotated method. 
    Packager.(Product product) 
    [parameter: Product product] 

Das bedeutet, dass, wenn ein Packager Objekt zu erstellen versuchen, es nicht eine geeignete Bindung für seine Product Parameter finden konnte. Der Weg, dies zu beheben, besteht darin, das Modul mit seiner Bindung von Product < ProductOne anzugeben.

@Component(modules = ProductOneModule.class) 
public interface PackagerOneComponent { 
    Packager packager(); 
} 

Jetzt weiß er, dass ein Product zu schaffen es ProductOneModule.provideProduct(ProductOne) und um aufrufen muss anrufen, dass es eine ProductOne erstellen muss, die es weiß, wie zu tun, weil Sie einen seiner Konstruktor mit @Inject markiert haben.

Natürlich, wenn Sie ProductTwo verwenden möchten, dann können Sie einfach ein anderes Modul und eine andere Komponente erstellen.

@Module 
public class ProductTwoModule { 
    @Provides Product provideProduct(ProductTwo productTwo) { 
    return productTwo; 
    } 
} 

@Component(modules = ProductTwoModule.class) 
public interface PackagerTwoComponent { 
    Packager packager(); 
} 

Das Problem bei einem Qualifikationsspiel in diesem Fall, entweder ein benutzerdefinierter einer oder Benannt ist, dass mit Qualifier Sie fest Paar der Injektionsstelle mit einer spezifischen Implementierung. Dies ist in einigen Fällen definitiv erforderlich, z. Wenn Sie zwei lange Instanzen haben, von denen eine eine Zeitüberschreitung und eine eine Zeitüberschreitung darstellt, möchten Sie nicht, dass sie verwechselt werden. Daher müssen Sie unbedingt Qualifikationsmerkmale verwenden, um sie zu unterscheiden.

In diesem Fall ist es jedoch wahrscheinlich, dass einige Benutzer oder die Verpackung ProductOne verwenden möchten und einige ProductTwo verwenden möchten. Andernfalls sollte Packager einfach ProductOne oder ProductTwo direkt nehmen und die Schnittstelle vermeiden.

Dieser Ansatz ermöglicht zwei verschiedene Teile Ihres Codes Packager mit zwei verschiedenen Implementierungen von Product, z. Ihre Produktion und Ihre Tests.

Natürlich können Sie zwei verschiedene Implementierungen verwenden, auch wenn sie mit einem Qualifier versehen sind, aber Sie müssen immer noch eine Vielzahl dieser Technik verwenden.

+0

Danke Paul. Zweite Technik ist auch gut. – vsvankhede

4

Dieses Beispiel funktioniert nicht. Wir müssen @Named Annotation für diesen Fall verwenden.

Für oben Beispiel in unserem Dagger Packaging-Modul müssen wir ProductOne und ProductTwo Abhängigkeit bereitstellen.

@Provides @Named("product one") Product provideProductOne() { 
    return new ProductOne(); 
} 


@Provides @Named("product two") Product provideProductTwo() { 
    return new ProductTwo(); 
} 

Jetzt, wenn wir diese Abhängigkeit injizieren müssen, können wir sie auf folgendem Weg injizieren.

public class Packaging{ 

Product product; 

@Inject 
public Packaging(@Named("product one") Product product){ 
    this.product = product; 
} 

} 

Wenn wir Instanz von ProductTwo dann brauchen.

public class Packaging{ 

Product product; 
@Inject 
public Packaging(@Named("product two")Product product){ 
    this.product = product; 
} 

} 

Diese @Named Anmerkung ist nichts anderes als die Verwendung von @Qualifier Anmerkung enthalten in javax.inject

@Qualifier 
@Documented 
@Retention(RUNTIME) 
public @interface Named { 
    String value() default ""; 
} 

Wir haben nicht diese Erklärung zu schaffen, damit Dagger dies für uns tun.

Verwandte Themen