2016-03-13 16 views
6

Ho il modulo Singleton con ambito che fornisce alcuni singleton standard: Applicazione, servizi DB, ecc. Ma per Attività ho un modulo separato che dovrebbe creare Presentatore per lui Attività e ho bisogno di passare il contesto dell'applicazione ad esso. Tuttavia ottengo seguente errore quando si tenta di compilare il progetto:Daga 2: Impossibile iniettare singleton in altro ambito

Error:(13, 1) error: xxx.SplashComponent scoped with @xxx.ViewScope may not reference bindings with different scopes: 
@Provides @Singleton xxx.ApplicationModule.provideAppContext() 

Ecco frammento di mio modulo di applicazione:

@Singleton 
@Module 
public class ApplicationModule { 

    private Application app; 

    public ApplicationModule(Application app) { 
     this.app = app; 
    } 

    @Provides 
    @Singleton 
    @Named("ui") 
    Scheduler provideUIScheduler() { 
     return AndroidSchedulers.mainThread(); 
    } 

    @Provides 
    @Singleton 
    @Named("io") 
    Scheduler provideIOScheduler() { 
     return Schedulers.io(); 
    } 

    @Provides 
    @Singleton 
    Application provideApplication() { 
     return app; 
    } 

    @Provides 
    @Singleton 
    Context provideAppContext() { 
     return app; 
    } 
} 

E qui è il modulo di attività e Componente:

@Module 
public class SplashModule { 
    private final FragmentManager fragmentManager; 

    public SplashModule(FragmentManager fragmentManager) { 

     this.fragmentManager = fragmentManager; 
    } 

    @Provides 
    @ViewScope 
    Presenter getPresenter(Context context) { 
     return new SplashPresenter(context, fragmentManager); 
    } 
} 

Component :

@ViewScope 
@Component(modules = {SplashModule.class, ApplicationModule.class}) 
public interface SplashComponent { 
    void inject(SplashActivity activity); 
} 

Cosa sto sbagliando?

+0

Grazie. Dopo aver esaminato il tuo messaggio di errore, ho capito che il mio file Module conteneva metodi con diversi ambiti. Ad esempio, "@ FirstScope @ Binds Class1 method1()" e "@ SecondScope @ Binds Class2 method2()". – CoolMind

risposta

7

Cosa sto sbagliando?

questo:

@ViewScope 
@Component(modules = {SplashModule.class /*View scoped*/, 
    ApplicationModule.class/*Singleton scoped*/}) 

È possibile includere solo senza ambito o moduli ambito con lo scopo stessa nei vostri componenti. Dovrai utilizzare più di un componente.

Per includere le dipendenze dall'applicazione, è necessario averli in un componente diverso, ad es. ApplicationComponent. Se lo fai, hai 2 opzioni: o dichiarare SplashComponent come SubComponent di ApplicationComponent o aggiungere ApplicationComponent come dipendenza dal componente. Se lo aggiungi come dipendenza, assicurati di fornire anche metodi nel tuo ApplicationComponent, in modo che possa accedere alle dipendenze.

ad es. se dovessi utilizzare le dipendenze dei componenti:

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

    void inject(MyApplication app); 

    // todo: also add getters for your other dependencies you need further down the graph 
    Application getApplication(); 

} 

@Component(modules = {SplashModule.class}, dependencies={ApplicationComponent.class}) 
public interface SplashComponent { 
    // as before 
} 
+7

Ancora non capisco –

4

Voglio spiegare alcuni punti chiave relativi a Dagger 2 dalla mia comprensione.

attori principali:

"componente" è il ponte tra i moduli e luoghi dove avviene l'iniezione.

"Modulo" è il luogo in cui dichiariamo i nostri oggetti che verranno iniettati.

"Scope" è come la durata della storia dell'iniezione correlata.

Come funziona?

-Declare componente con un ambito ("Singleton").

-Definire gli oggetti che possono iniettare gli oggetti forniti nel modulo del componente.

iniettare void (BaseFragment baseFragment);

******* Esporre gli oggetti forniti nel modulo del componente ai componenti secondari ****
DbHelper dbHelper();

-Dichiara modulo e fornisce oggetti da iniettare tramite componente.

Es:

@Singleton 
@Component(modules = { ApplicationModule.class, NetworkModule.class }) 
public interface ApplicationComponent { 

    void inject(BaseActivity baseActivity); 
    DbHelper dbHelper(); 
} 




@PerService @Component(dependencies = ApplicationComponent.class, modules = ServiceModule.class) 
public interface ServiceComponent { 

    void inject(SyncService service); 

} 

// SyncService.java

@Inject DbHelper dbHelper; (even Singleton scoped) 

    private void setupInjector() { 
    ServiceComponent mServiceComponent = DaggerServiceComponent.builder() 
     .applicationComponent(getApplicationComponent()) 
     .serviceModule(new ServiceModule(this)) 
     .build(); 
    mServiceComponent.inject(this); 
    } 

ok allora ... enter image description here

è possibile iniettare sia senza ambito e (Singleton e PerService) scope oggetti per la vostra SyncService.class

+0

Esporre roba come 'DbHelper dbHelper()' era quello che mi mancava tutto il tempo. Grazie mille per questa risposta. –

+0

Devo correggerti un po 'su "Singleton è l'impostazione predefinita". No-scope è il valore predefinito non Singleton. Senza @Singleton avrai una nuova istanza ad ogni iniezione. – WindRider

+0

@WindRider hai ragione. Ecco perché abbiamo contrassegnato alcuni componenti come Singleton per evitare di creare ogni volta costosi oggetti. – huseyin

Problemi correlati