2015-04-23 9 views
7

Ich habe ein einfaches Dagger 2 Test-Setup, basierend auf http://konmik.github.io/snorkeling-with-dagger-2.html. Es injiziert einen PreferenceLogger, der alle Einstellungen ausgibt. In der injizierten Klasse kann ich @ weitere Klassen einlesen.Dolch 2 und Schnittstellenimplementierungen

public class MainActivity extends Activity { 
    @Inject PreferencesLogger logger; 
    @Inject MainPresenter presenter; 

    @Override protected void onCreate(Bundle savedInstanceState) { 
    MyApplication.getComponent().inject(this); 
    presenter.doStuff(); 
     logger.log(this); 
    } 
} 


public class PreferencesLogger { 

    @Inject OkHttpClient client; 
    @Inject public PreferencesLogger() {} 

    public void log(Contect context) { 
    // this.client is available 
    } 
} 

Als ich dies ausführen, wird Logger gesetzt, und im Inneren PreferencesLogger.log wird der OkHttpClient richtig eingestellt ist. So funktioniert dieses Beispiel wie erwartet. Jetzt versuche ich, eine MVP-Struktur an Ort und Stelle zu bekommen. Es gibt eine MainPresenter-Schnittstelle mit einer Implementierung. Im MainActivity stelle ich ein:

@Inject MainPresenter presenter; 

so konnte ich diese MainPresenter mit einem alternativen Schalter (Debug oder Test) Implementierung. Natürlich brauche ich jetzt ein Modul, um festzulegen, welche Implementierung ich verwenden möchte.

Ein Problem tritt jetzt auf, dass der OkHttpClient nicht mehr injiziert wird. Natürlich könnte ich das Modul ändern, um einen Parameter OkHttpClient zu akzeptieren, aber ich denke nicht, dass dies der vorgeschlagene Weg ist. Gibt es einen Grund, warum der MainPresenterImpl nicht korrekt inject?

+0

fragte ich eine ähnliche Frage hier: http://stackoverflow.com/questions/30555285/dagger2-injecting-implementation-classes-with-component – EpicPandaForce

+0

in diesem Artikel und Beispielprojekt einen Blick darauf werfen, die helfen können: https://medium.com/@m_mirhoseini/yet-another-mvp-article-part-1-lets-get-to-know-the-project-d3fd553b3e21#.6y9ze7e55 –

Antwort

4

Im Gegensatz zur Konstruktorinjektion können die @Inject annotierten Felder von Abhängigkeiten, die in @Provides Methoden konstruiert wurden, nicht automatisch injiziert werden. Die Fähigkeit, Felder zu injizieren, erfordert eine Komponente, die den Typ des Feldes in seinen Modulen bereitstellt, und in den Provider-Methoden selbst ist eine solche Implementierung nicht verfügbar.

Wenn das Feld presenter in MainActivity injiziert wird, wird nur die Providermethode aufgerufen und presenter wird auf seinen Rückgabewert gesetzt. In Ihrem Beispiel führt der No-Args-Konstruktor keine Initialisierung durch, und auch die Provider-Methode, so dass keine Initialisierung stattfindet.

Die Provider-Methode hat jedoch Zugriff auf Instanzen anderer Typen, die über ihre Parameter im Modul bereitgestellt werden. Ich denke, die Verwendung von Parametern in der Provider-Methode ist in der Tat die vorgeschlagene (sogar die einzige) Möglichkeit, die Abhängigkeiten des bereitgestellten Typs zu "injizieren", da sie explizit als Abhängigkeiten innerhalb des Moduls angegeben werden, wodurch Dagger einen Fehler beim Kompilieren auslösen kann -Zeit, wenn sie nicht zufrieden sein können.

Der Grund ist es zur Zeit keinen Fehler werfen, weil MainPresenterImplkönnte seine OkHttpClient Abhängigkeit zufrieden, wenn MainPresenterImpl und nicht MainPresenter irgendwo ein Ziel für die Injektion ist. Dolch kann keine Member-Injection-Methode für den Interface-Typ erstellen, da es als Schnittstelle keine injizierbaren Felder haben kann und die Felder des Implementierungstyps nicht automatisch injiziert, da es nur die Provider-Methode liefert kehrt zurück.

4

Sie könnten Ihre MainPresenterImpl mit Konstruktor Injektion injizieren.

/* unscoped */ 
public class MainPresenterImpl implements MainPresenter { 

    @Inject 
    OkHttpClient client; 

    @Inject 
    public MainPresenterImpl() { 
    } 

    @Override public void doStuff() { 
     // this.client is now available! :) 
    } 
} 


@Module 
public class AppModule { 
    private MyApplication application; 

    public AppModule(MyApplication application) { 
     this.application = application; 
    } 

    @Provides 
    /* unscoped */ 
    public MyApplication application() { 
     return application; 
    } 
} 

@Module 
public abstract class MainActivityModule { 
    @Binds public abstract MainPresenter mainPresenter(MainPresenterImpl mainPresenterImpl); 
}