Uso Dagger2 per DI nella mia applicazione Android. Ho scoperto che devo scrivere il metodo di iniezione per ogni classe che utilizza il campo @Inject. C'è un modo in cui posso semplicemente iniettare la classe genitore in modo che non debba chiamare inietti su ogni sottoclasse? Prendi Attività ad esempio. Ho un BaseActivity
da cui si estende ogni attività. C'è un modo in cui posso semplicemente creare un metodo di iniezione nel componente per BaseActivity e chiamare semplicemente iniettare in BaseActivity onCreate, e i campi @inject nelle attività secondarie vengono iniettati automaticamente?Posso solo iniettare una super classe quando uso dagger2 per l'iniezione di dipendenza?
risposta
Al momento non è possibile. Spiegazione da Gregory Calcio:
Ecco come metodi membri iniezione funzionano:
- si può fare un metodo di membri di iniezione per ogni tipo che ha
@Inject
ovunque nella sua gerarchia di classe. In caso contrario, riceverai un errore .- Tutti i membri di
@Inject
verranno inseriti nella gerarchia di tipi: il tipo di argomento e tutti i supertipi.- Nessun membro sarà
@Inject
per sottotipi del tipo di argomento.
Questo problema è stato discusso e herehere, follow-up di questi per gli aggiornamenti. Ma è improbabile che cambi presto, perché Dagger 2 è close to release.
Sembra che abbiano preso questa decisione per un motivo. Ma è ancora un peccato che non lo supportino poiché è un piccolo IMHO contro-intuitivo. Comunque, grazie per la risposta! –
@ Chris.Zou Per supportare l'iniezione in sottoclasse, è necessario eseguire la reflection in fase di esecuzione. Il team di Dagger 2 ha deciso fin da subito di voler evitare di fare cose in fase di esecuzione, poiché è più lento e non si scoprono gli errori finché non si esegue l'app. – vaughandroid
Ho riscontrato la stessa situazione. Un modo per facilitare un po 'l'iniezione da un componente comune in tutte le attività è il seguente:
1) Estendere la classe dell'applicazione per poter creare il componente comune e mantenere un riferimento ad esso.
public class ApplicationDagger extends Application {
private ApplicationComponent component;
@Override
public void onCreate(){
super.onCreate();
component = DaggerApplicationComponent.builder().applicationModule(new ApplicationModule(this)).build();
}
public ApplicationComponent getComponent(){
return component;
}
}
2) Creare un DaggerActivity astratta che ottiene la componente comune da parte delle applicazioni e chiama un metodo astratto injectActivity
, dando il componente come argomento. Come questo:
public abstract class DaggerActivity extends Activity {
@Override
public void onCreate(Bundle saved){
super.onCreate(saved);
ApplicationComponent component = ((ApplicationDagger) getApplication()).getComponent();
injectActivity(component);
}
public abstract void injectActivity(ApplicationComponent component);
}
3) Ultimo, si deve iniettare in realtà ogni Activity
estende DaggerActivity
. Ma questo può essere fatto con meno sforzi ora, dato che devi implementare il metodo abstract
altrimenti otterrai degli errori di compilazione. Andiamo:
public class FirstActivity extends DaggerActivity {
@Inject
ClassToInject object;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//initialize your Activity
}
@Override
public void injectActivity(ApplicationComponent component) {
component.inject(this);
}
}
Naturalmente, è ancora necessario dichiarare ogni attività esplicitamente nel componente.
UPDATE: Iniettare @ActivityScope oggetti in frammenti
Ad un certo punto, avevo bisogno di usare custom scopes per associare gli oggetti a un ciclo di vita Activity
. Ho deciso di estendere questo post in quanto potrebbe aiutare alcune persone.
Diciamo che avete un @modulo classe ActivityModule
e @Subcomponent interfaccia ActivityComponent
.
È necessario modificare lo DaggerActivity
. Il Activities
che estende DaggerActivity
dovrebbe implementare il nuovo metodo (modifica della firma).
public abstract class ActivityDagger extends AppCompatActivity {
ComponentActivity component;
@Override
protected void onCreate(Bundle savedInstanceState) {
component = ((ApplicationDagger) getApplication()).getComponent().plus(new ActivityModule(this));
injectActivity(component);
super.onCreate(savedInstanceState);
}
ActivityComponent getComponent() {
return component;
}
public abstract void injectActivity(ActivityComponent component);
}
Poi, una classe FragmentDagger
estendentesi Fragment
possono essere creati in questo modo:
public abstract class FragmentDagger extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityDagger activityDagger = (ActivityDagger) getActivity();
ActivityComponent component = activityDagger.getComponent();
injectFragment(component);
}
public abstract void injectFragment(ActivityComponent component);
}
Quanto al Activities
, il Fragments
estende FragmentDagger
hanno solo un metodo per implementare:
public abstract void injectFragment(ActivityComponent component);
Dovresti essere in grado di riutilizzare lo Fragments
ovunque tu voglia. Si noti che il metodo ActivityDagger
in ActivityDagger
deve essere chiamato dopo l'istanza del componente. In caso contrario, verrà visualizzato NullPointerException quando viene ricreato lo stato Activity
, in quanto verrà chiamato il metododello Fragment
.
Grazie per il suggerimento! –
si può fare un piccolo hack utilizzando la riflessione:
public class UiInjector {
private static final String METHOD_NAME = "inject";
private final UIComponent component;
public UiInjector(final UIComponent component) {
this.component = component;
}
public void inject(final Object subject) {
try {
component.getClass()
.getMethod(METHOD_NAME, subject.getClass())
.invoke(component, subject);
} catch (final NoSuchMethodException exception) {
throwNoInjectMethodForType(component, subject.getClass());
} catch (final Exception exception) {
throwUnknownInjectionError(exception);
}
}
private void throwNoInjectMethodForType(final Object component, final Class subjectType) {
throw new RuntimeException(component.getClass().getSimpleName() +
" doesn't have inject method with parameter type : " + subjectType);
}
private void throwUnknownInjectionError(final Exception cause) {
throw new RuntimeException("Unknown injection error", cause);
}
}
In questo caso, è ancora necessario per scrivere il metodo di iniettare in un componente, ma non hai bisogno di 'iniettare' metodo in ogni attività, frammento, vista, qualunque cosa.
Perché è lavoro? quando usiamo getClass()
sul soggetto dell'iniezione otterremo una classe discendente, non base.
Attenzione! Nel caso in cui si usi Proguard, è necessario aggiungere il successivo -keep class <ComponentClass> { *; }
alle proprie regole per mantenere i metodi di iniezione come è nel componente
- 1. Iniettare una dipendenza all'interno di un oggetto
- 2. Come iniettare un fagiolo solo quando esiste
- 3. Come si fornisce una dipendenza di GoogleApiClient con Dagger2?
- 4. grafico dipendenza dipendenza per una classe java
- 5. Angolare 2 - Iniettare una dipendenza in una fabbrica di arredatori
- 6. Come iniettare dipendenze in qualsiasi tipo di oggetto con Dagger2?
- 7. E 'possibile iniettare una dipendenza "ovunque" automaticamente?
- 8. In Python, come posso chiamare la super-classe quando si tratta di una namedtuple una tantum?
- 9. valore Iniettare in dipendenza iniettato
- 10. Sovraccarico di una funzione di super classe
- 11. chiamata metodo di classe super super
- 12. Java: uso di super() nell'esempio fornito
- 13. Come iniettare dipendenza dal frammento Android nidificato?
- 14. Python: Perché non posso usare `super` su una classe?
- 15. Guice - Iniettare dipendenza in una classe con metodi di supporto statici
- 16. Iniezione dipendenza ASP.NET 5, iniettare con parametri
- 17. Creazione di dipendenze di test quando si utilizza Dagger2
- 18. Quando si chiama super() in una classe derivata, posso passare in self .__ class__?
- 19. Quando si deride una classe con Moq, come posso chiamare CallBase solo per metodi specifici?
- 20. come iniettare proprietà di dipendenza utilizzando Ioc Unità
- 21. Iniettare struttura utilizzando @Value di classe astratta
- 22. Assegnare una sottoclasse di una classe generica a una classe super-di questa classe
- 23. Come iniettare nome dipendenza come parametro del costruttore
- 24. Uso di "super" con "?" in Java
- 25. Uso obsoleto di una classe come classe genitore in Python
- 26. Perché "[auto classe] == [super classe]"?
- 27. Come escludere una dipendenza solo per un ambito specifico?
- 28. Angular2: Iniettare una classe @Injectable non
- 29. Come far riflettere Java per individuare i campi nella super classe? non solo la classe attuale
- 30. componente Dagger2 con più di un dipendenze
Potresti aggiungere qualche codice di esempio per mostrare cosa intendi? – nhaarman