Manuelle Abhängigkeitsinjektion oder -dienst in einer Android-App kann die Suche je nach Größe Projekt arbeiten. Sie können die Komplexität Ihres Projekts beim Skalieren begrenzen, indem Sie Dagger zum Verwalten von Abhängigkeiten
Dagger generiert automatisch Code, der den Code nachahmt, den Sie sonst erhalten würden. handschriftlich sind. Da der Code bei der Kompilierung generiert wird, kann er nachverfolgt werden. und leistungsstärker als andere reflexionsbasierte Lösungen wie Guice:
Vorteile von Dagger
Mit Dagger müssen Sie keinen lästigen und fehleranfälligen Boilerplate-Code mehr schreiben:
Manuelles Generieren des
AppContainer
-Codes (Anwendungsdiagramm) manuell im DI-Abschnitt implementiert.Erstellen von Factories für die im Anwendungsdiagramm verfügbaren Klassen. Dieses wie Abhängigkeiten intern befriedigt werden.
Entscheiden, ob eine Abhängigkeit wiederverwendet oder über die Methode Verwendung von Bereichen
Container für bestimmte Abläufe erstellen, wie Sie es beim Anmeldevorgang in der im vorherigen Abschnitt mit den Unterkomponenten von Dagger. Das verbessert die Leistung deiner App indem Sie Objekte im Arbeitsspeicher freigeben, wenn sie nicht mehr benötigt werden.
Das alles geschieht bei der Erstellung automatisch, solange Sie Abhängigkeiten einer Klasse deklarieren und mithilfe von Anmerkungen. Dagger generiert Code, der dem entspricht, was Sie geschrieben hätten manuell. Intern erstellt Dagger ein Diagramm mit Objekten, auf die es verweisen kann. um eine Möglichkeit zu finden, eine Instanz einer Klasse bereitzustellen. Für jede Klasse in der Grafik Dagger generiert eine factory-type-Klasse, die es verwendet. um Instanzen dieses Typs abzurufen.
Zum Zeitpunkt der Build-Erstellung geht Dagger Ihren Code durch und:
Erstellt und validiert Abhängigkeitsdiagramme. Dabei wird sichergestellt, dass:
- Die Abhängigkeiten jedes Objekts können erfüllt werden, sodass es keine Laufzeit gibt Ausnahmen.
- Es gibt keine Abhängigkeitszyklen, daher gibt es auch keine Endlosschleifen.
Erzeugt die Klassen, die zur Laufzeit zum Erstellen der tatsächlichen Objekte und ihrer Abhängigkeiten verwendet werden.
Ein einfacher Anwendungsfall in Dagger: Factory generieren
Um zu demonstrieren, wie Sie mit Dagger arbeiten können, erstellen wir ein einfaches
factory für die Klasse UserRepository
fest, die im
folgendes Diagramm:
Definieren Sie UserRepository
so:
Kotlin
class UserRepository( private val localDataSource: UserLocalDataSource, private val remoteDataSource: UserRemoteDataSource ) { ... }
Java
public class UserRepository { private final UserLocalDataSource userLocalDataSource; private final UserRemoteDataSource userRemoteDataSource; public UserRepository(UserLocalDataSource userLocalDataSource, UserRemoteDataSource userRemoteDataSource) { this.userLocalDataSource = userLocalDataSource; this.userRemoteDataSource = userRemoteDataSource; } ... }
Fügen Sie dem UserRepository
-Konstruktor eine @Inject
-Anmerkung hinzu, damit Dagger weiß,
So erstellen Sie eine UserRepository
:
Kotlin
// @Inject lets Dagger know how to create instances of this object class UserRepository @Inject constructor( private val localDataSource: UserLocalDataSource, private val remoteDataSource: UserRemoteDataSource ) { ... }
Java
public class UserRepository { private final UserLocalDataSource userLocalDataSource; private final UserRemoteDataSource userRemoteDataSource; // @Inject lets Dagger know how to create instances of this object @Inject public UserRepository(UserLocalDataSource userLocalDataSource, UserRemoteDataSource userRemoteDataSource) { this.userLocalDataSource = userLocalDataSource; this.userRemoteDataSource = userRemoteDataSource; } }
Im obigen Code-Snippet teilen Sie Dagger mit:
So erstellen Sie eine
UserRepository
-Instanz mit der annotierten@Inject
-Konstruktor.Die Abhängigkeiten sind:
UserLocalDataSource
undUserRemoteDataSource
.
Jetzt weiß Dagger, wie eine Instanz von UserRepository
erstellt wird,
wie die Abhängigkeiten erstellt werden. Wenn Sie auch die anderen Klassen annotieren,
Dagger weiß, wie diese erstellt werden:
Kotlin
// @Inject lets Dagger know how to create instances of these objects class UserLocalDataSource @Inject constructor() { ... } class UserRemoteDataSource @Inject constructor() { ... }
Java
public class UserLocalDataSource { @Inject public UserLocalDataSource() { } } public class UserRemoteDataSource { @Inject public UserRemoteDataSource() { } }
Dolchkomponenten
Dagger kann ein Diagramm der Abhängigkeiten in Ihrem Projekt erstellen,
um herauszufinden, woher diese Abhängigkeiten kommen,
wenn sie benötigt werden.
Dazu müssen Sie eine Schnittstelle erstellen und mit Anmerkungen versehen
@Component
Dagger erstellt wie bei der manuellen Erstellung einen Container.
Abhängigkeitsinjektion.
Innerhalb der @Component
-Schnittstelle können Sie Funktionen definieren, die
Instanzen der benötigten Klassen (z.B. UserRepository
). @Component
teilt Ihnen mit
Dagger zum Generieren eines Containers mit allen Abhängigkeiten, die für die
Typen angezeigt werden. Dies wird als Dagger-Komponente bezeichnet. es enthält
ein Diagramm mit den Objekten, die Dagger weiß,
und ihren jeweiligen Abhängigkeiten.
Kotlin
// @Component makes Dagger create a graph of dependencies @Component interface ApplicationGraph { // The return type of functions inside the component interface is // what can be provided from the container fun repository(): UserRepository }
Java
// @Component makes Dagger create a graph of dependencies @Component public interface ApplicationGraph { // The return type of functions inside the component interface is // what can be consumed from the graph UserRepository userRepository(); }
Beim Erstellen des Projekts generiert Dagger eine Implementierung der
ApplicationGraph
-Oberfläche für Sie: DaggerApplicationGraph
. Mit der
erstellt Dagger ein Abhängigkeitsdiagramm, das aus den
Beziehungen zwischen den drei Klassen (UserRepository
,
UserLocalDatasource
und UserRemoteDataSource
) mit nur einem Einstiegspunkt:
Abrufen einer UserRepository
-Instanz Sie können es wie folgt verwenden:
Kotlin
// Create an instance of the application graph val applicationGraph: ApplicationGraph = DaggerApplicationGraph.create() // Grab an instance of UserRepository from the application graph val userRepository: UserRepository = applicationGraph.repository()
Java
// Create an instance of the application graph ApplicationGraph applicationGraph = DaggerApplicationGraph.create(); // Grab an instance of UserRepository from the application graph UserRepository userRepository = applicationGraph.userRepository();
Dagger erstellt bei jeder Anfrage eine neue Instanz von UserRepository
.
Kotlin
val applicationGraph: ApplicationGraph = DaggerApplicationGraph.create() val userRepository: UserRepository = applicationGraph.repository() val userRepository2: UserRepository = applicationGraph.repository() assert(userRepository != userRepository2)
Java
ApplicationGraph applicationGraph = DaggerApplicationGraph.create(); UserRepository userRepository = applicationGraph.userRepository(); UserRepository userRepository2 = applicationGraph.userRepository(); assert(userRepository != userRepository2)
Manchmal benötigen Sie eine eindeutige Instanz einer Abhängigkeit in einem Container. Dies kann verschiedene Gründe haben:
Sie möchten, dass andere Typen, die diesen Typ als Abhängigkeit haben, denselben wie z. B. mehrere
ViewModel
-Objekte im Anmeldevorgang mit demselbenLoginUserData
.Die Erstellung eines Objekts ist teuer und Sie möchten kein neues erstellen -Instanz jedes Mal, wenn sie als Abhängigkeit deklariert wird (z. B. ein JSON-Parser).
In diesem Beispiel benötigen Sie möglicherweise eine eindeutige Instanz von UserRepository
.
in der Grafik angezeigt. Jedes Mal, wenn Sie nach einem UserRepository
fragen,
erhalten immer dieselbe Instanz. Dies ist in Ihrem Beispiel nützlich,
einer realen Anwendung mit einer komplexeren Anwendungsgrafik,
mehrere ViewModel
-Objekte abhängig von UserRepository
und Sie möchten
zum Erstellen neuer Instanzen von UserLocalDataSource
und UserRemoteDataSource
jedes Mal, wenn UserRepository
angegeben werden muss.
Bei der manuellen Abhängigkeitsinjektion übergeben Sie dasselbe
Instanz von UserRepository
für die Konstruktoren der ViewModel-Klassen; aber
Da Sie diesen Code nicht manuell schreiben,
Dagger weiß, dass Sie dieselbe Instanz verwenden möchten. Dies kann mithilfe des Umfangs
Anmerkungen.
Geltungsbereich mit Dolch
Sie können Bereichsanmerkungen verwenden, um die Lebensdauer eines Objekts auf die Lebensdauer zu begrenzen. seiner Komponente. Dies bedeutet, dass dieselbe Instanz einer Abhängigkeit verwendet wird wenn dieser Typ bereitgestellt werden muss.
Um eine eindeutige Instanz von UserRepository
zu haben, wenn Sie nach dem Repository fragen
Verwenden Sie in ApplicationGraph
dieselbe Bereichsanmerkung für @Component
.
und UserRepository
. Mit der Anmerkung @Singleton
können Sie
ist bereits im javax.inject
-Paket enthalten, das von Dagger verwendet wird:
Kotlin
// Scope annotations on a @Component interface informs Dagger that classes annotated // with this annotation (i.e. @Singleton) are bound to the life of the graph and so // the same instance of that type is provided every time the type is requested. @Singleton @Component interface ApplicationGraph { fun repository(): UserRepository } // Scope this class to a component using @Singleton scope (i.e. ApplicationGraph) @Singleton class UserRepository @Inject constructor( private val localDataSource: UserLocalDataSource, private val remoteDataSource: UserRemoteDataSource ) { ... }
Java
// Scope annotations on a @Component interface informs Dagger that classes annotated // with this annotation (i.e. @Singleton) are scoped to the graph and the same // instance of that type is provided every time the type is requested. @Singleton @Component public interface ApplicationGraph { UserRepository userRepository(); } // Scope this class to a component using @Singleton scope (i.e. ApplicationGraph) @Singleton public class UserRepository { private final UserLocalDataSource userLocalDataSource; private final UserRemoteDataSource userRemoteDataSource; @Inject public UserRepository(UserLocalDataSource userLocalDataSource, UserRemoteDataSource userRemoteDataSource) { this.userLocalDataSource = userLocalDataSource; this.userRemoteDataSource = userRemoteDataSource; } }
Alternativ können Sie eine benutzerdefinierte Umfangsanmerkung erstellen und verwenden. So erstellen Sie eine Bereichsanmerkung:
Kotlin
// Creates MyCustomScope @Scope @MustBeDocumented @Retention(value = AnnotationRetention.RUNTIME) annotation class MyCustomScope
Java
// Creates MyCustomScope @Scope @Retention(RetentionPolicy.RUNTIME) public @interface MyCustomScope {}
Anschließend können Sie es wie zuvor verwenden:
Kotlin
@MyCustomScope @Component interface ApplicationGraph { fun repository(): UserRepository } @MyCustomScope class UserRepository @Inject constructor( private val localDataSource: UserLocalDataSource, private val service: UserService ) { ... }
Java
@MyCustomScope @Component public interface ApplicationGraph { UserRepository userRepository(); } @MyCustomScope public class UserRepository { private final UserLocalDataSource userLocalDataSource; private final UserRemoteDataSource userRemoteDataSource; @Inject public UserRepository(UserLocalDataSource userLocalDataSource, UserRemoteDataSource userRemoteDataSource) { this.userLocalDataSource = userLocalDataSource; this.userRemoteDataSource = userRemoteDataSource; } }
In beiden Fällen wird dem Objekt derselbe Bereich bereitgestellt, mit dem das Objekt annotiert wird.
@Component
-Schnittstelle. Daher sollten Sie jedes Mal, wenn Sie
applicationGraph.repository()
, erhalten Sie dieselbe Instanz von
UserRepository
.
Kotlin
val applicationGraph: ApplicationGraph = DaggerApplicationGraph.create() val userRepository: UserRepository = applicationGraph.repository() val userRepository2: UserRepository = applicationGraph.repository() assert(userRepository == userRepository2)
Java
ApplicationGraph applicationGraph = DaggerApplicationGraph.create(); UserRepository userRepository = applicationGraph.userRepository(); UserRepository userRepository2 = applicationGraph.userRepository(); assert(userRepository == userRepository2)
Fazit
Es ist wichtig, die Vorteile und die Funktionsweise von Dagger zu kennen. bevor Sie sie in komplizierteren Szenarien einsetzen können.
Auf der nächsten Seite erfahren Sie, wie Sie Dagger einer Android-App hinzufügen.