2016-04-25 17 views
8

Ho appena iniziato a utilizzare Dagger 2 e ho trovato migliaia di guide online ognuna con un'implementazione diversa e sono un po 'confuso ora. Quindi, in pratica questo è ciò che ho scritto in questo momento:Iniezione presentatore con Dagger 2

AppModule.java:

@Module 
public class AppModule { 

Application mApplication; 

public AppModule(Application application) { 
    mApplication = application; 
} 

@Provides 
@Singleton 
Application providesApplication() { 
    return mApplication; 
} 
} 

DataModule.java:

@Module 
public class DataModule { 

private static final String BASE_URL = "http://beta.fridgewizard.com:9001/api/"; 

@Provides 
@Singleton 
NetworkService provideNetworkService() { 
    return new NetworkService(BASE_URL); 
} 

@Provides 
@Singleton 
SharedPreferences provideSharedPreferences(Application app) { 
    return PreferenceManager.getDefaultSharedPreferences(app); 
} 
} 

PrefsModel.java:

@Module(includes = DataModule.class) 
public class PrefsModel { 

@Provides 
@Singleton 
QueryPreferences provideQuery(SharedPreferences prefs) { 
    return new QueryPreferences(prefs); 
} 
} 

AppComponent .java (Sto esponendo oggetti QueryPreferences poiché ne ho bisogno in un presenter, si spera è corretto in questo modo):

@Singleton 
@Component(modules = {AppModule.class, DataModule.class, PrefsModel.class}) 
public interface AppComponent { 

    void inject(HomeFragment homeFragment); 

    QueryPreferences preferences(); 
    NetworkService networkService(); 
} 

allora ho il FwApplication.java:

public class FwApplication extends Application { 

private static final String TAG = "FwApplication"; 

private NetworkService mNetworkService; 

private AppComponent mDataComponent; 

    @Override 
    public void onCreate() { 
     super.onCreate(); 

     buildComponentAndInject(); 
    } 

    public static AppComponent component(Context context) { 
     return ((FwApplication) context.getApplicationContext()).mDataComponent; 
    } 

    public void buildComponentAndInject() { 
     mDataComponent = DaggerComponentInitializer.init(this); 
    } 

    public static final class DaggerComponentInitializer { 
     public static AppComponent init(FwApplication app) { 
     return DaggerAppComponent.builder() 
       .appModule(new AppModule(app)) 
       .dataModule(new DataModule()) 
       .build(); 
    } 
    } 
} 

Infine ho aggiunto un altro modulo per i presentatori:

@Module 
public class PresenterModule { 

    @Provides 
    Presenter<FwView> provideHomePresenter(NetworkService networkService) { 
     return new HomePresenterImpl(networkService); 
    } 

    @Provides 
    Presenter<FwView> provideSearchPresenter(NetworkService networkService) { 
     return new SearchPresenterImpl(networkService); 
    } 

} 

E il seguente componente (che restituisce errore perché non riesco ad aggiungere le dipendenze con scope qui):

@Component(dependencies = AppComponent.class, modules = PresenterModule.class) 
public interface PresenterComponent { 

    void inject(HomePresenterImpl presenter); 
} 

Così, ho alcune domande che non sono chiare per me la lettura della documentazione in linea:

  • Come posso correggere l'errore nel componente presentatore in quanto dipende NetworkService che è un Singleton definito nel AppComponent?
  • Ho un HomeFragment che dovrebbe attuare la HomePresenter con "nuova HomePresenter (NetworkService)", ma ora non so come usare il DI definito

EDIT - FIX:

HomeFragment .java:

public class HomeFragment extends Fragment { 

private static final String TAG = "FW.HomeFragment"; 


@Inject 
HomePresenterImpl mHomePresenter; 

public static HomeFragment newInstance() { 
    return new HomeFragment(); 
} 

@Override 
public void onCreate(@Nullable Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    FwApplication.component(getActivity()).inject(this); 
} 

Poi ho modificato il costruttore presentatore in questo modo:

@Inject 
public HomePresenterImpl(NetworkService networkService) { 
    mNetworkService = networkService; 
    mInteractor = new InteractorImpl(mNetworkService); 
} 

Quindi NetworkService viene iniettato automaticamente.

Mi chiedevo se è corretto in questo modo da quando devo chiamare per ogni frammento che ho che ha bisogno di un presentatore costruito nello stesso modo come quello sopra il seguente codice:

FwApplication.component(getActivity()).inject(this); 
+0

'correggi l'errore nel componente del presentatore 'per favore * sempre * include l'errore –

+1

' '' getAactivity() '' 'usato in' '' onCreate() '' 'può produrre' '' NullPointerException'''. http://stackoverflow.com/a/6225044/1888738 – Bresiu

risposta

11

Sei mescolando cose. Per fornire il tuo relatore, devi passare a qualcosa di simile al seguente:

Utilizzare l'iniezione del costruttore se possibile.Renderà le cose molto più facile

public class HomePresenterImpl { 

    @Inject 
    public HomePresenterImpl(NetworkService networkService) { 
     // ... 
    } 

} 

Per fornire l'uso dell'interfaccia questo costruttore injecetion e dipendono sull'attuazione

Presenter<FwView> provideHomePresenter(HomePresenterImpl homePresenter) { 
    return homePresenter; 
} 

In questo modo non c'è bisogno di chiamare qualsiasi costruttori stessi. E in realtà iniettare il presentatore ...

public class MyFragment extends Fragment { 

    @Inject 
    Presenter<FwView> mHomePresenter; 

    public void onCreate(Bundle xxx) { 
     // simplified. Add your modules/Singleton component 
     PresenterComponent component = DaggerPresenterComponent.create().inject(this); 
    } 
} 

In questo modo si inietta le cose. Si prega di leggere attentamente e cercare di capirlo. Ciò risolverà i vostri problemi importanti, non è ancora possibile fornire 2 presentatori dello stesso tipo e dello stesso modulo (nello stesso ambito)

// DON'T 
@Provides 
Presenter<FwView> provideHomePresenter(NetworkService networkService) { /**/ } 

@Provides 
Presenter<FwView> provideSearchPresenter(NetworkService networkService) { /**/ } 

Questo no lavoro. Non puoi fornire 2 oggetti dello stesso tipo. Sono indistinguibili. Dai uno sguardo allo @Qualifiers come @Named se sei sicuro che questo è il modo in cui vuoi andare.

+0

Grazie mille per la risposta, ho modificato la domanda per mostrare come l'ho risolto seguendo i vostri consigli. (Non sono sicuro di come ho fatto l'iniezione di Presenter nel frammento) – user1341300

+2

@David per il tuo 'return homePresenter;' puoi usare l'annotazione '@ Binds', che può generare un codice migliore dietro le quinte. Vedi https://google.github.io/dagger/faq.html#binds e https://google.github.io/dagger/api/latest/dagger/Binds.html – TWiStErRob

+0

Grazie mille! Anch'io stavo lottando con me stesso. Questo ha chiarito alcuni dei miei dubbi. Grazie ancora. – taitasciore

4

Non è necessario fornire Presenter se l'annotazione @Inject viene utilizzata nel costruttore. L'annotazione @Inject utilizzata nel costruttore della classe rende tale classe parte del grafico delle dipendenze. Quindi, può anche essere iniettato quando necessario.

D'altra parte, se si aggiunge l'annotazione @Inject ai campi, ma non ai costruttori, è necessario fornire tale classe.

Problemi correlati