Ich benutze Dagger2 für DI in meiner Android-Anwendung. Ich fand, dass ich inject-Methode für jede Klasse schreiben muss, die @Inject-Feld verwendet. Gibt es eine Möglichkeit, dass ich einfach die Elternklasse injizieren kann, damit ich nicht auf jede Unterklasse injizieren muss? Nehmen Sie zum Beispiel Aktivität. Ich habe eine BaseActivity
, dass jede Aktivität erstreckt sich von. Gibt es eine Möglichkeit, dass ich einfach eine inject-Methode in der Komponente für BaseActivity erstellen kann und einfach inject in BaseActivity onCreate aufruft, und @inject-Felder in Unteraktivitäten automatisch injiziert werden?Kann ich nur Super-Klasse injizieren, wenn Sie dagger2 für die Dependency-Injektion verwenden?
Antwort
Es kann nicht sofort gemacht werden. Erklärung von Gregory Stoss-Schützen:
Hier ist, wie Mitglieder Injektionsverfahren arbeiten:
- Sie können ein Mitglieder-Injektionsverfahren für jede Art machen, die
@Inject
überall in seiner Klassenhierarchie hat. Wenn nicht, erhalten Sie einen Fehler.- Alle
@Inject
ed-Member in der gesamten Typhierarchie werden injiziert: der Argumenttyp und alle Supertypen.- Keine Mitglieder werden
@Inject
Ed für Subtypes des Argumenttyps.
Dieses Problem wurde here und here, diskutiert diese Updates folgen zu lassen. Aber es ist unwahrscheinlich, dass sich das bald ändert, denn Dagger 2 ist close to release.
Es scheint, dass sie diese Entscheidung aus einem bestimmten Grund getroffen haben. Aber es ist immer noch schade, dass sie das nicht unterstützen, da es ein wenig kontraintuitiv ist. Trotzdem, danke für die Antwort! –
@ Chris.Zou Um die Subklasseninjektion zu unterstützen, müssten Sie zur Laufzeit Reflektion durchführen. Das Dagger 2-Team hat schon früh entschieden, dass sie es vermeiden wollen, Dinge zur Laufzeit zu tun, da es langsamer ist und man erst dann Fehler erfährt, wenn man die App startet. – vaughandroid
Ich stieß auf die gleiche Situation. Eine Möglichkeit, die Injektion aus einer gemeinsamen Komponente in allen Aktivitäten etwas zu erleichtern, ist die folgende:
1) Erweitern Sie die Application-Klasse, um die gemeinsame Komponente erstellen zu können und einen Verweis darauf zu behalten.
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) Erstellen Sie eine abstrakte DaggerActivity, die die gemeinsame Komponente von Anwendungs bekommt und ruft eine abstrakte Methode injectActivity
, die Komponente als Argument zu geben. Wie folgt aus:
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) Last, müssen Sie injizieren tatsächlich jede Activity
DaggerActivity
erstreckt. Dies kann jedoch jetzt mit weniger Aufwand erfolgen, da Sie die Methode abstract
implementieren müssen, da sonst Kompilierungsfehler auftreten. Hier gehen wir:
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);
}
}
Natürlich müssen Sie noch jede Aktivität explizit in Ihrer Komponente deklarieren.
UPDATE: Injecting @ActivityScope in Fragmente Objekte
, Irgendwann musste ich custom scopes verwenden, um Objekte zu binden, zu einem Activity
Lebenszyklus. Ich habe beschlossen, diesen Beitrag auszuweiten, da es einigen Leuten helfen könnte.
Angenommen, Sie haben eine ActivityComponent
@Module Klasse ActivityModule
und eine @Subcomponent Schnittstelle.
Sie müssten die DaggerActivity
ändern. Die Activities
Erweiterung DaggerActivity
müsste die neue Methode (Signaturwechsel) implementieren.
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);
}
Dann wird eine Klasse FragmentDagger
Fragment
erstrecken kann wie folgt erstellt werden:
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);
}
Was die Activities
, die Fragments
FragmentDagger
erstreckt haben nur eine Methode zu implementieren:
public abstract void injectFragment(ActivityComponent component);
Sie sollten in der Lage sein, Fragments
wo immer Sie wollen wiederzuverwenden. Beachten Sie, dass die Methode super.onCreated()
in ActivityDagger
nach der Komponenteninstanziierung aufgerufen werden sollte. Andernfalls erhalten Sie NullPointerException, wenn der Activity
-Status neu erstellt wird, da die Methode super.onCreate()
des Fragment
aufgerufen wird.
Danke für den Tipp! –
Sie können ein wenig Hack tun Reflexion mit:
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 diesem Fall müssen Sie noch Methode in einer Komponente injizieren schreiben, aber Sie brauchen nicht 'Inject' Methode in jeder Aktivität, Fragment, Ansicht, was auch immer.
Warum es funktioniert? wenn wir getClass()
auf der Einspritzung verwenden, erhält Subjekt eine Nachkommenklasse, nicht Basis.
Vorsicht! Wenn Sie Proguard verwenden, müssen Sie als nächstes -keep class <ComponentClass> { *; }
zu Ihren Regeln hinzufügen, um die Injekt-Methoden so zu behalten, wie in Komponente
- 1. Injecting OkHttpClient mit Dagger2
- 2. Kann ich eine Methode aus einer Superklasse in einer Unterklasse verwenden, ohne sie zu überschreiben?
- 3. Dagger2 - null statt injiziert Objekt
- 4. XJC Superinterface und Superklasse nur für alle Klassen?
- 5. Injizieren der abgeleiteten Eigenschaft für @Repository-Bean ohne @Autowired in der Superklasse
- 6. Verwenden Sie ServiceWorker-Cache nur, wenn offline
- 7. Aktivitätsumfang von Dagger2, wie viele Module/Komponenten benötige ich?
- 8. Schrifttyp für Ansichtshalter TextView mit Dagger2 DI
- 9. Wie kann ich zweite databaseContext für API-Konfiguration injizieren
- 10. Rufen Sie eine Methode aus der Superklasse der Superklasse
- 11. Sie können die berechnete Variable nur mit Setter und Getter verwenden, um die gespeicherte Eigenschaft der Superklasse zu überschreiben
- 12. Kann ich Clojure Multimethods nur für Java-Klassen verwenden?
- 13. Keine Dagger2 generierte Dateien für JUnit Tests
- 14. Wenn ich versuche, UI-Automatisierung für PowerPoint 2013 zu verwenden, kann ich nur das erste Zeichen/Wort verwenden, wenn ich RangeFromPoint verwenden
- 15. Kann ich ASP.NET Core Targeting nur für .NET 4.6.1 verwenden?
- 16. Inject Federabhängigkeit in abstrakte Superklasse
- 17. Verwenden von ArrayLists in Superklasse/Unterklassenframework
- 18. Welche Abhängigkeiten sollte ich injizieren?
- 19. Verwenden Sie die Standardwerte von web.config, wenn Sie Webbereitstellungsparameter verwenden
- 20. Verwenden Sie fiddler nur für einige Prozesse
- 21. Wie kann ich Location in angular2 injizieren?
- 22. Kann ich eine iPhone-Anwendung entwickeln, die mein Unternehmen nur für interne Mitarbeiter verwenden kann?
- 23. Laravel - Automatische Benötigte Schnittstellen Injizieren Wenn Sie manuell eine Klasse
- 24. Dagger2 Subkomponente Modul überschreiben
- 25. kann ich Werte in die Datei persistence.xml von Maven injizieren?
- 26. Die Superklasse aller Event-Klassen
- 27. wie Skript nur für den ersten Körper injizieren?
- 28. Warum kann ich mit Ninjects ConstructorArgument keinen Wert null injizieren?
- 29. Kann ich die Java-Sprache für Robolectric-Tests verwenden, während ich Java7 für die App verwende?
- 30. Kann ich eine Facebook-App erstellen, die nur ich verwenden kann?
Könnten Sie einen Beispielcode hinzufügen, um zu zeigen, was Sie meinen? – nhaarman