2015-04-23 11 views
7

Mam prosty zestaw testowy Dagger 2, oparty na http://konmik.github.io/snorkeling-with-dagger-2.html. To wstrzykuje PreferenceLogger, który wyprowadza wszystkie preferencje. W klasie iniekcyjnej mogę dodać więcej zajęć.Implementacja Dagger 2 i interfejsu

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

Kiedy uruchomić tego rejestratora jest ustawiony, a wewnątrz PreferencesLogger.log OkHttpClient jest prawidłowo ustawiony. Ten przykład działa zgodnie z oczekiwaniami. Teraz próbuję uzyskać strukturę MVP. Istnieje interfejs MainPresenter z implementacją. W MainActivity ustawiłem:

@Inject MainPresenter presenter; 

, więc mogłem zmienić tę MainPresenter na alternatywną (debugową lub testową) implementację. Oczywiście, teraz potrzebuję modułu, aby określić, jakiej implementacji chcę użyć.

public interface MainPresenter { 
    void doStuff(); 
} 

public class MainPresenterImpl implements MainPresenter { 

    @Inject OkHttpClient client; 

    public MainPresenterImpl() {} 

    @Override public void doStuff() { 
    // this.client is not available  
    } 
} 


@Module public class MainActivityModule { 
    @Provides MainPresenter provideMainPresenter() { 
     return new MainPresenterImpl(); 
    } 
} 

Problem pojawia się teraz, że OkHttpClient nie wstrzykuje już. Oczywiście mogę zmienić moduł, aby zaakceptować parametr OkHttpClient, ale nie sądzę, że jest to sugerowany sposób na zrobienie tego. Czy istnieje powód, dla którego MainPresenterImpl nie wstrzykuje się prawidłowo?

+0

zapytałem powiązane pytanie tutaj: http://stackoverflow.com/questions/30555285/dagger2-injecting-implementation-classes-with-component – EpicPandaForce

+0

spojrzeć na ten artykuł i przykładowy projekt, który może pomóc: https://medium.com/@m_mirhoseini/yet-another-mvp-article-part-1-lets-get-t--n--project-d3fd553b3e21#.6y9ze7e55 –

Odpowiedz

4

Inaczej niż przy iniekcji konstruktora, nie można automatycznie wstrzykiwać pól opatrzonych adnotacjami opatrzonych @Inject skonstruowanymi w metodach @Provides. Możliwość wstawiania pól wymaga komponentu, który zapewnia typ pola w jego modułach, a także w samych metodach dostawcy, taka implementacja nie jest dostępna.

Gdy pole presenter jest wstrzykiwane w MainActivity, wszystko, co się dzieje, to wywołanie metody dostawcy, a presenter jest ustawiona na wartość zwracaną. W twoim przykładzie konstruktor no-args nie inicjuje ani metoda dostawcy, więc nie ma inicjalizacji.

Metoda dostawcy ma jednak dostęp do wystąpień innych typów dostarczanych w module za pośrednictwem jego parametrów. Myślę, że używanie parametrów w metodzie providera jest w rzeczywistości sugerowanym (nawet jedynym) sposobem "wstrzyknięcia" zależności podanego typu, ponieważ wyraźnie wskazuje je jako zależności w module, co pozwala Daggerowi na zgłoszenie błędu podczas kompilacji czas, jeśli nie mogą być usatysfakcjonowani.

Powodem obecnie nie wygeneruje błąd dlatego MainPresenterImplmógłby dostać jego OkHttpClient zależność spełniony, jeżeli MainPresenterImpl i nie MainPresenter gdzieś cel do wstrzykiwań. Sztylet nie może wykonać metody wtrysku dla członków dla typu interfejsu, ponieważ jako interfejs nie może mieć pól do wstrzykiwania i nie będzie automatycznie wstawiał pól typu implementującego, ponieważ dostarcza tylko dowolną metodę dostawcy zwraca.

4

Możesz wstrzyknąć swoją MainPresenterImpl za pomocą wstrzyknięcia konstruktora.

/* 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); 
} 
Powiązane problemy