2015-09-01 11 views
5

La mia configurazione di pugnale per un progetto Android su cui sto lavorando: Nota: ho fornito tutte le necessarie annotazioni @Component, @Module, @Provides ovunque sia necessario.Iniezione a più componenti indipendenti

MainActivity { 

@Inject A a; 
@Inject B b; 

onCreate(){ 
    ComponentX.inject(this); 
    ComponentY.inject(this); 
} 
} 

ComponentX-> ModuleA ->providerA 
ComponentY -> ModuleB -> providerB 

Come si può vedere, si tratta di due componenti completamente indipendenti tra loro non in alcun modo tranne che nel punto di iniezione.

Durante la compilazione ottengo il seguente errore:

In file A.java 
error: B cannot be provided without an @Provides- or @Produces-annotated method. 
MainActivity.b 
[injected field of type: B b] 

mi sbaglio a pensare che più componenti può essere utilizzato durante l'utilizzo di pugnale 2 o è l'applicazione dovrebbe utilizzare una grande componente che si occupa di tutti i iniezioni?

Qualcuno può aiutarmi a capire dove sto andando male?

risposta

7

Non è necessario avere un singolo componente, ci sono vari modi per rendere modulare loro, ma ogni oggetto che si crea, o iniettare valori in, deve avere tutti i suoi valori forniti da un singolo componente.

Un modo per ristrutturare il codice è che ComponentY dipenda da ComponentX o viceversa, ad es.

@Component(dependencies = ComponentX.class) 
interface ComponentY { 
    void inject(MainActivity activity); 
} 

Oppure si potrebbe creare un terzo componente, dicono ComponentZ, se componentX e componentY sono completamente ortogonali tra loro.

@Component(dependencies = {ComponentX.class, ComponentY.class}) 
interface ComponentZ { 
    void inject(MainActivity activity); 
} 

Oppure si potrebbe semplicemente riutilizzare i moduli, ad es.

@Component(modules = {ModuleA.class, ModuleB.class}) 
interface ComponentZ { 
    void inject(MainActivity activity); 
} 

Come esattamente si decide di dividerlo dipende in gran parte dalla struttura del codice. Se i componenti X e Y sono visibili ma i moduli non lo sono, usa le dipendenze dei componenti, in quanto esse (e le dipendenze del modulo) sono in realtà dettagli di implementazione del componente. Altrimenti, se i moduli sono visibili, li riutilizzi semplicemente.

Non utilizzerei gli scope per questo dato che sono veramente utili per gestire oggetti con durate diverse, ad es. oggetti associati a un utente specifico la cui durata è il tempo a partire dal momento in cui un utente accede al momento del logout o la durata di una richiesta specifica. Se hanno una durata di vita diversa, stai cercando di utilizzare ambiti e sottocomponenti.

+0

Il metodo di composizione è quello che ho fatto attualmente come soluzione intermedia. D'altra parte, dalla mia comprensione, gli ambiti erano un uso diverso proprio come hai detto tu. Quello che volevo identificare era se questo fosse l'approccio giusto, componente di iniezione target singolo che è una composizione di più componenti (che sono forniti in progetti di libreria) – gaara87

+0

È sicuramente un buon approccio, se è l'approccio giusto dipende da voi. Di nuovo dipende da cosa è la tua 'API' e come vuoi modularla. –

+0

È sicuramente un buon approccio, se è l'approccio giusto dipende da te. Di nuovo dipende da cosa è la tua 'API' e come vuoi modularla. –

0

is the application supposed to use one big component which takes care of all the injections?

È possibile utilizzare Subcomponent. Nei tuoi componenti caso di dichiarazione sarà simile a questa:

@Subcomponent(modules=ModuleB.class) 
public interface ComponentY{ 
    void inject(MainActivity mainActivity); 
} 

@Component(modules=ModuleA.class) 
public interface ComponentX{ 
    ComponentY plus(ModuleB module); 
} 

ComponentY creazione: creationCompunentY = ComponentX.plus(new ModuleB());

Ora in MainActivity si chiamano solo ComponentY.inject(this);

MainActivity { 

@Inject A a; 
@Inject B b; 

onCreate(){ 
    ComponentY.inject(this); 
} 
} 

ulteriori informazioni sui componenti secondari può essere trovato in migration from Dagger1 guide (guarda la parte dei sottografi), Subcomponent JavaDoc e Component JavaDoc (guarda la sezione Sottocomponenti).

+0

Anche in questo caso si sta parlando di comporre tutto in un unico grande componente che si prende cura delle iniezioni. Non stai esattamente affrontando lo scenario di avere due componenti separati. Avendo due inietti separati – gaara87

+0

penso che la composizione del componente finale prima di usarlo sia molto meglio che fare un'iniezione multipla come suggerisci tu. Il tuo 'MainActivity' non dovrebbe sapere come le tue dipendenze sono distribuite tra' Componenti'. Ci sono due o tre componenti, ecc. E tu sei libero di cambiare quella distribuzione per fornire test più semplici o un riutilizzo più semplice senza cambiare 'MainActivity'. – MyDogTom

+0

@ MyDogTom Non sono d'accordo sul fatto che la composizione di un componente "grasso" sia migliore. Vorrei che la libertà iniettasse le cose direttamente in classe. In entrambi i modi, MainActivity non ha idea della creazione di componenti e si preoccupa solo di ciò che viene iniettato in esso. Non ti sto dicendo che hai torto, solo che questa è una prospettiva diversa, ma la vedo come una limitazione. –

2

is the application supposed to use one big component

In genere, dovresti pensarci negli ambiti. Per un dato ambito, c'è un componente. Gli ambiti sono ad esempio ApplicationScope, FragmentScope (conservato), ActivityScope, ViewScope. Per ogni ambito, c'è un dato componente; gli ambiti non sono condivisi tra i componenti.

(Ciò significa essenzialmente che se si desidera avere singleton globali nello @ApplicationScope, esiste un componente con ambito applicazione per esso. Se si desidera classi specifiche dell'attività, quindi si crea un componente per tale attività specifica, che dipenderà dal componente dell'ambito dell'applicazione).

Fare riferimento a @MyDogTom per l'annotazione @Subcomponent, ma è anche possibile utilizzare le dipendenze del componente per la creazione di componenti sottoposti a sottoscrizione.

@YScope 
@Component(dependencies = ComponentX.class, modules=ModuleB.class) 
public interface ComponentY extends ComponentX { 
    B b(); 

    void inject(MainActivity mainActivity); 
} 

@XScope 
@Component(modules=ModuleA.class) 
public interface ComponentX{ 
    A a(); 
} 

ComponentY componentY = DaggerComponentY.builder().componentX(componentX).build(); 
+0

1) Compilare per te? Perché questi sono due ambiti diversi. 2) In definitiva, si sta parlando di un componente estendendo il componente Y dal componenteX. Hai preso la via dell'ereditarietà e stavo pensando al percorso della composizione (scegliendo la dipendenza tra componenti). – gaara87

+0

Ovviamente compila se aggiungi le due annotazioni del mirino personalizzato, YScope è un subscope di XScope. Think ActivityScope è un subscope di ApplicationScope. – EpicPandaForce

Problemi correlati