2013-07-15 4 views
8

Sto usando Dagger per iniettare dipendenze in un'applicazione Android , e mi sono imbattuto in un problema che non sono del tutto sicuro come risolvere in modo pulito.Daga e iniezioni nidificate

Quello che sto cercando di ottenere è di instal- dare gli helper e iniettarli all'interno della mia attività e avere questi helper anche con membri iniettati.

Nei funziona

L'attività in cui viene iniettato il mio aiuto:

public class MyActivity extends Activity { 
    @Inject SampleHelper helper; 

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

     ((MyApplication) getApplication()).inject(this); 

     Log.i("debug", "helper = " + helper); 
     Log.i("debug", "helper context = " + helper.context); 
    } 
} 

La domanda creando il grafo:

public class MyApplication extends Application { 
    private ObjectGraph graph; 

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

     graph = ObjectGraph.create(getModules()); 
    } 

    private Object[] getModules() { 
     return new Object[] { new MyModule(this) }; 
    } 

    public void inject(Object target) { 
     graph.inject(target); 
    } 
} 

L'iniezione funziona perfettamente quando instanciate direttamente una classe SampleHelper, che a sua volta riceve una domanda iniettata ntext:

@Singleton 
public class SampleHelper { 

    @Inject public Context context; 

    @Inject 
    public SampleHelper() {} 
} 

Con il seguente modulo:

@Module(
    injects = { MyActivity.class }, 
    complete = false, 
    library = true 
) 
public class MyModule { 
    private final MyApplication application; 

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

    @Provides @Singleton Context provideApplicationContext() { 
     return application; 
    } 
} 

cosa non funziona

Tuttavia, quando separo l'interfaccia di supporto dalla sua attuazione:

public interface SampleHelper { 
} 

@Singleton 
public class SampleHelperImpl implements SampleHelper { 

    @Inject public Context context; 

    @Inject 
    public SampleHelperImpl() {} 
} 

E aggiungilo al modulo del pugnale:

public class MyModule { 
    ... 

    // added this method 
    @Provides @Singleton public SampleHelper provideSampleHelper() { 
     return new SampleHelperImpl(); 
    } 

    ... 
} 

Il contesto non viene iniettato nel mio SampleHelperImpl, come mi sarei aspettato. Ora, immagino che questo sia dovuto al fatto che SampleHelperImpl viene instanciato tramite chiamata diretta al costruttore piuttosto che chiamata costruttore avviata dall'iniezione, perché MyModule # provideApplicationContext() non viene nemmeno chiamato, quindi la mia ipotesi è che manchi qualcosa su Dagger (che è probabile, dal momento che le mie precedenti esperienze con DI hanno incluso solo Spring).

Qualche idea su come inserire il mio contesto nella mia implementazione di helper iniettata, in un modo "clean Dagger"?

Grazie mille!

+0

Al momento sto lottando anche con il pugnale e ho una configurazione simile alla tua. Ho bisogno di iniettare istanze di attività in helpers, non applicazioni in sé, ma per il resto è molto simile. Ecco perché ho una domanda per te: perché immetti il ​​contesto come membro in "SampleHelper", non come parametro costruttore? Nel mio caso, l'iniezione tramite il parametro del costruttore fallisce e quindi mi chiedo se c'è qualcosa di speciale a riguardo, che dovrebbe essere evitato. Capisco che sia fuori tema, ma se puoi aiutare, sarebbe apprezzato. – Haspemulator

+0

Attualmente, passo il contesto come parametro costruttore (come menzionato nella mia risposta sotto), sebbene non sia iniettato direttamente nel costruttore stesso, ma piuttosto come parte di un metodo @Provides nel modulo dagger (e funziona) . La mia idea iniziale era quella di eliminare tutto il codice relativo all'assegnazione dei miei membri grazie al pugnale, ma non riuscivo a renderlo facile da usare come, ad esempio, l'iniezione di primavera. Detto questo, sono consapevole che non funzionano allo stesso modo e con gli stessi vincoli, e il pugnale porta ancora molto. – mrlem

+0

Ciao, grazie per la risposta. Forse puoi dare un'occhiata alla mia domanda? http://stackoverflow.com/questions/17839451/activity-graphs-and-non-found-dependency – Haspemulator

risposta

17

Questa è una domanda piuttosto vecchio, ma penso che quello che vuoi è questo:

@Provides @Singleton public SampleHelper provideSampleHelper(SampleHelperImpl impl) { 
    return impl; 
} 

In questo modo Dagger creerà il vostro SampleHelperImpl e quindi iniettarlo.

+0

Non troppo tardi: risponde perfettamente alla mia domanda. Molte grazie! – mrlem

+0

@alexanderblom Potresti spiegare la differenza tra ciò che hai fatto e ciò che ha fatto mrlem? – peacepassion

1

Nel caso in cui qualcuno è interessato, in sede di attuazione di un metodo @Provides in un modulo pugnale, è possibile ottenere le istanze di oggetti pugnale dal manico del genere:

@Provides @Singleton public SampleHelper provideSampleHelper(Context context) { 
    SampleHelper helper = new SampleHelperImpl(); 
    helper.setContext(context); 
    return helper; 
} 

Questo funziona, ma mi sento ancora è un po 'goffa , come devo chiamare esplicitamente i miei aiutanti setter (tipicamente ciò di cui vuoi liberarti con l'iniezione).

(Aspetterò un po 'nel caso in cui qualcuno viene fornito con una soluzione migliore)

0

In termini di iniettare il giusto contesto si potrebbe desiderare di avere uno sguardo a questo campione https://github.com/square/dagger/tree/master/examples/android-activity-graphs.

+0

Grazie per la risposta: ho già trovato questo esempio (non ce n'è moltissimo ;). In effetti, in un'app di vita reale, è necessario iniettare il giusto contesto. Ma la mia domanda iniziale era un po 'più generale: separare l'interfaccia Helper dall'implementazione impedisce a @Inject di funzionare all'interno dell'implementazione, poiché l'istanziazione dell'helper non viene più gestita direttamente da Dagger. – mrlem

1

(Si applica a Dagger v1.0.1)

Assicurarsi di utilizzare l'iniezione dell'adattatore. Con l'iniezione riflessa, il pugnale apparentemente non fa un'iniezione transitiva sugli oggetti @Provides. Penso che questo sia un bug.

+1

Sembra proprio il mio problema. Ma potresti per favore chiarire due cose: 1/ho pensato che non usasse la riflessione per le sue iniezioni? (che cosa suppongo intendessi per "iniezione riflessiva", o intendevi iniezione basata sull'annotazione?) 2/cosa intendi per iniezione dell'adattatore: iniezioni usando @Provides nel modulo del pugnale? – mrlem

+0

Dagger fornisce due modi per impostare i campi annotati '@ Inject'. Uno è via riflessione, l'altro è tramite una classe adattatore generata. In entrambi i casi i campi devono essere almeno accessibili ai pacchetti. Il metodo di riflessione è un fallback e potrebbe non essere disponibile nelle versioni futur. Per verificare quale metodo di iniezione si sta utilizzando, impostare un punto di interruzione nel metodo '@ Fornisce' del modulo ed esaminare la traccia dello stack. Guardare fuori per: 'injectMembers(): 118, ReflectiveAtInjectBinding {} dagger.internal.plugins.reflect' vs 'injectMembers(): 82, YourClassname $$ InjectAdapter {} your.classes.package' –

+0

Ok, grazie per il chiarimento, cercherò di verificarlo! – mrlem