Hilt ist eine Dependency Injection-Bibliothek für Android, die den Boilerplate-Code für die manuelle Dependency Injection in Ihrem Projekt reduziert. Bei der manuellen Abhängigkeitsinjektion müssen Sie jede Klasse und ihre Abhängigkeiten manuell erstellen und Container verwenden, um Abhängigkeiten wiederzuverwenden und zu verwalten.
Hilt bietet eine Standardmethode zur Verwendung von DI in Ihrer Anwendung. Dazu stellt es Container für jede Android-Klasse in Ihrem Projekt bereit und verwaltet deren Lebenszyklen automatisch. Hilt basiert auf der beliebten DI-Bibliothek Dagger, um von der Korrektheit bei der Kompilierung, der Laufzeitleistung, der Skalierbarkeit und der Android Studio-Unterstützung zu profitieren, die Dagger bietet. Weitere Informationen finden Sie unter Knauf und Dolch.
In diesem Leitfaden werden die grundlegenden Konzepte von Hilt und die generierten Container erläutert. Außerdem wird gezeigt, wie eine vorhandene App für die Verwendung von Hilt gestartet wird.
Abhängigkeiten hinzufügen
Fügen Sie zuerst das hilt-android-gradle-plugin
-Plug-in der Stammdatei build.gradle
Ihres Projekts hinzu:
Groovy
plugins { ... id 'com.google.dagger.hilt.android' version '2.51.1' apply false }
Kotlin
plugins { ... id("com.google.dagger.hilt.android") version "2.51.1" apply false }
Wenden Sie dann das Gradle-Plug-in an und fügen Sie der Datei app/build.gradle
die folgenden Abhängigkeiten hinzu:
Groovy
... plugins { id 'kotlin-kapt' id 'com.google.dagger.hilt.android' } android { ... } dependencies { implementation "com.google.dagger:hilt-android:2.51.1" kapt "com.google.dagger:hilt-compiler:2.51.1" } // Allow references to generated code kapt { correctErrorTypes true }
Kotlin
plugins { id("kotlin-kapt") id("com.google.dagger.hilt.android") } android { ... } dependencies { implementation("com.google.dagger:hilt-android:2.51.1") kapt("com.google.dagger:hilt-android-compiler:2.51.1") } // Allow references to generated code kapt { correctErrorTypes = true }
Hilt verwendet Java 8-Funktionen. Wenn Sie Java 8 in Ihrem Projekt aktivieren möchten, fügen Sie der Datei app/build.gradle
Folgendes hinzu:
Groovy
android { ... compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } }
Kotlin
android { ... compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } }
Hilt-Anwendungsklasse
Alle Apps, die Hilt verwenden, müssen eine Application
-Klasse enthalten, die mit @HiltAndroidApp
annotiert ist.
@HiltAndroidApp
löst die Codegenerierung von Hilt aus, einschließlich einer Basisklasse für Ihre Anwendung, die als Abhängigkeitscontainer auf Anwendungsebene dient.
Kotlin
@HiltAndroidApp class ExampleApplication : Application() { ... }
Java
@HiltAndroidApp public class ExampleApplication extends Application { ... }
Diese generierte Hilt-Komponente ist mit dem Lebenszyklus des Application
-Objekts verknüpft und stellt Abhängigkeiten dafür bereit. Außerdem ist es die übergeordnete Komponente der App. Das bedeutet, dass andere Komponenten auf die von ihr bereitgestellten Abhängigkeiten zugreifen können.
Abhängigkeiten in Android-Klassen einschleusen
Sobald Hilt in Ihrer Application
-Klasse eingerichtet ist und eine Komponente auf Anwendungsebene verfügbar ist, kann Hilt Abhängigkeiten zu anderen Android-Klassen mit der Anmerkung @AndroidEntryPoint
bereitstellen:
Kotlin
@AndroidEntryPoint class ExampleActivity : AppCompatActivity() { ... }
Java
@AndroidEntryPoint public class ExampleActivity extends AppCompatActivity { ... }
Hilt unterstützt derzeit die folgenden Android-Klassen:
Application
(mit@HiltAndroidApp
)ViewModel
(mit@HiltViewModel
)Activity
Fragment
View
Service
BroadcastReceiver
Wenn Sie eine Android-Klasse mit @AndroidEntryPoint
annotieren, müssen Sie auch alle Android-Klassen annotieren, die davon abhängen. Wenn Sie beispielsweise ein Fragment annotieren, müssen Sie auch alle Aktivitäten annotieren, in denen Sie dieses Fragment verwenden.
@AndroidEntryPoint
generiert eine einzelne Hilt-Komponente für jede Android-Klasse in Ihrem Projekt. Diese Komponenten können Abhängigkeiten von ihren jeweiligen übergeordneten Klassen erhalten, wie in der Komponentenhierarchie beschrieben.
Wenn Sie Abhängigkeiten von einer Komponente abrufen möchten, verwenden Sie die Anmerkung @Inject
, um eine Feldinjektion durchzuführen:
Kotlin
@AndroidEntryPoint class ExampleActivity : AppCompatActivity() { @Inject lateinit var analytics: AnalyticsAdapter ... }
Java
@AndroidEntryPoint public class ExampleActivity extends AppCompatActivity { @Inject AnalyticsAdapter analytics; ... }
Klassen, die von Hilt injiziert werden, können andere Basisklassen haben, die ebenfalls die Injektion verwenden.
Für diese Klassen ist die Anmerkung @AndroidEntryPoint
nicht erforderlich, wenn sie abstrakt sind.
Weitere Informationen dazu, in welchen Lebenszyklus-Callbacks eine Android-Klasse eingefügt wird, finden Sie unter Lebensdauer von Komponenten.
Hilt-Bindungen definieren
Für die Feldinjektion muss Hilt wissen, wie Instanzen der erforderlichen Abhängigkeiten aus der entsprechenden Komponente bereitgestellt werden. Eine Bindung enthält die Informationen, die erforderlich sind, um Instanzen eines Typs als Abhängigkeit bereitzustellen.
Eine Möglichkeit, Hilt Bindungsinformationen zur Verfügung zu stellen, ist die Konstruktor-Injection. Verwenden Sie die Annotation @Inject
am Konstruktor einer Klasse, um Hilt anzuweisen, wie Instanzen dieser Klasse bereitgestellt werden sollen:
Kotlin
class AnalyticsAdapter @Inject constructor( private val service: AnalyticsService ) { ... }
Java
public class AnalyticsAdapter { private final AnalyticsService service; @Inject AnalyticsAdapter(AnalyticsService service) { this.service = service; } ... }
Die Parameter eines annotieren Konstruktors einer Klasse sind die Abhängigkeiten dieser Klasse. In diesem Beispiel hat AnalyticsAdapter
AnalyticsService
als Abhängigkeit. Daher muss Hilt auch wissen, wie Instanzen von AnalyticsService
bereitgestellt werden.
Hilt-Module
Manchmal kann ein Typ nicht über den Konstruktor eingefügt werden. Das kann mehrere Gründe haben. Sie können beispielsweise keine Schnittstelle über den Konstruktor einschleusen. Außerdem können Sie keinen Typ über den Konstruktor einschleusen, der nicht Ihnen gehört, z. B. eine Klasse aus einer externen Bibliothek. In diesen Fällen können Sie Hilt mithilfe von Hilt-Modulen Bindungsinformationen zur Verfügung stellen.
Ein Hilt-Modul ist eine Klasse, die mit @Module
annotiert ist. Wie ein Dagger-Modul informiert es Hilt darüber, wie Instanzen bestimmter Typen bereitgestellt werden. Im Gegensatz zu Dagger-Modulen müssen Hilt-Module mit @InstallIn
annotiert werden, um Hilt mitzuteilen, in welcher Android-Klasse jedes Modul verwendet oder installiert wird.
Abhängigkeiten, die Sie in Hilt-Modulen angeben, sind in allen generierten Komponenten verfügbar, die mit der Android-Klasse verknüpft sind, in der Sie das Hilt-Modul installieren.
Schnittstelleninstanzen mit @Binds einfügen
Sehen wir uns das Beispiel AnalyticsService
an. Wenn AnalyticsService
eine Schnittstelle ist, kann sie nicht über den Konstruktor eingefügt werden. Stellen Sie Hilt stattdessen die Bindungsinformationen zur Verfügung, indem Sie in einem Hilt-Modul eine abstrakte Funktion mit @Binds
annotieren.
Die @Binds
-Anmerkung gibt Hilt an, welche Implementierung verwendet werden soll, wenn eine Instanz einer Schnittstelle bereitgestellt werden muss.
Die kommentierte Funktion stellt Hilt die folgenden Informationen zur Verfügung:
- Der Rückgabetyp der Funktion gibt an, für welche Schnittstelle die Funktion Instanzen bereitstellt.
- Der Funktionsparameter gibt Hilt an, welche Implementierung bereitgestellt werden soll.
Kotlin
interface AnalyticsService { fun analyticsMethods() } // Constructor-injected, because Hilt needs to know how to // provide instances of AnalyticsServiceImpl, too. class AnalyticsServiceImpl @Inject constructor( ... ) : AnalyticsService { ... } @Module @InstallIn(ActivityComponent::class) abstract class AnalyticsModule { @Binds abstract fun bindAnalyticsService( analyticsServiceImpl: AnalyticsServiceImpl ): AnalyticsService }
Java
public interface AnalyticsService { void analyticsMethods(); } // Constructor-injected, because Hilt needs to know how to // provide instances of AnalyticsServiceImpl, too. public class AnalyticsServiceImpl implements AnalyticsService { ... @Inject AnalyticsServiceImpl(...) { ... } } @Module @InstallIn(ActivityComponent.class) public abstract class AnalyticsModule { @Binds public abstract AnalyticsService bindAnalyticsService( AnalyticsServiceImpl analyticsServiceImpl ); }
Das Hilt-Modul AnalyticsModule
ist mit @InstallIn(ActivityComponent.class)
annotiert, weil Sie möchten, dass Hilt diese Abhängigkeit in ExampleActivity
einfügt. Diese Anmerkung bedeutet, dass alle Abhängigkeiten in AnalyticsModule
in allen Aktivitäten der App verfügbar sind.
Instanzen mit @Provides einschleusen
Schnittstellen sind nicht der einzige Fall, in dem Sie einen Typ nicht über den Konstruktor einschleusen können.
Die Konstruktor-Injection ist auch nicht möglich, wenn Sie nicht der Eigentümer der Klasse sind, weil sie aus einer externen Bibliothek stammt (Klassen wie Retrofit, OkHttpClient
oder Room-Datenbanken) oder wenn Instanzen mit dem Builder-Muster erstellt werden müssen.
Denken Sie an das vorherige Beispiel. Wenn Sie nicht direkt Inhaber der AnalyticsService
-Klasse sind, können Sie Hilt anweisen, wie Instanzen dieses Typs bereitgestellt werden sollen. Erstellen Sie dazu eine Funktion in einem Hilt-Modul und annotieren Sie diese Funktion mit @Provides
.
Die kommentierte Funktion liefert Hilt die folgenden Informationen:
- Der Rückgabetyp der Funktion gibt Hilt an, welchen Typ die Funktion bereitstellt.
- Die Funktionsparameter geben Hilt die Abhängigkeiten des entsprechenden Typs an.
- Im Funktionskörper wird Hilt mitgeteilt, wie eine Instanz des entsprechenden Typs bereitgestellt werden soll. Hilt führt den Funktionskörper jedes Mal aus, wenn eine Instanz dieses Typs bereitgestellt werden muss.
Kotlin
@Module @InstallIn(ActivityComponent::class) object AnalyticsModule { @Provides fun provideAnalyticsService( // Potential dependencies of this type ): AnalyticsService { return Retrofit.Builder() .baseUrl("https://example.com") .build() .create(AnalyticsService::class.java) } }
Java
@Module @InstallIn(ActivityComponent.class) public class AnalyticsModule { @Provides public static AnalyticsService provideAnalyticsService( // Potential dependencies of this type ) { return new Retrofit.Builder() .baseUrl("https://example.com") .build() .create(AnalyticsService.class); } }
Mehrere Bindungen für denselben Typ angeben
Wenn Hilt unterschiedliche Implementierungen desselben Typs als Abhängigkeiten bereitstellen soll, müssen Sie Hilt mehrere Bindungen zur Verfügung stellen. Mit Qualifikatoren können Sie mehrere Bindungen für denselben Typ definieren.
Ein Kvalifikator ist eine Anmerkung, mit der Sie eine bestimmte Bindung für einen Typ angeben, wenn für diesen Typ mehrere Bindungen definiert sind.
Sehen wir uns ein Beispiel an. Wenn Sie Aufrufe an AnalyticsService
abfangen möchten, können Sie ein OkHttpClient
-Objekt mit einem Interceptor verwenden. Bei anderen Diensten müssen Sie Anrufe möglicherweise auf andere Weise abfangen. In diesem Fall müssen Sie Hilt mitteilen, wie zwei verschiedene Implementierungen von OkHttpClient
bereitgestellt werden sollen.
Definieren Sie zuerst die Qualifier, mit denen Sie die @Binds
- oder @Provides
-Methoden annotieren möchten:
Kotlin
@Qualifier @Retention(AnnotationRetention.BINARY) annotation class AuthInterceptorOkHttpClient @Qualifier @Retention(AnnotationRetention.BINARY) annotation class OtherInterceptorOkHttpClient
Java
@Qualifier @Retention(RetentionPolicy.RUNTIME) private @interface AuthInterceptorOkHttpClient {} @Qualifier @Retention(RetentionPolicy.RUNTIME) private @interface OtherInterceptorOkHttpClient {}
Dann muss Hilt wissen, wie eine Instanz des Typs bereitgestellt wird, die jedem Qualifier entspricht. In diesem Fall können Sie ein Hilt-Modul mit @Provides
verwenden.
Beide Methoden haben denselben Rückgabetyp, aber die Qualifikationen kennzeichnen sie als zwei unterschiedliche Bindungen:
Kotlin
@Module @InstallIn(SingletonComponent::class) object NetworkModule { @AuthInterceptorOkHttpClient @Provides fun provideAuthInterceptorOkHttpClient( authInterceptor: AuthInterceptor ): OkHttpClient { return OkHttpClient.Builder() .addInterceptor(authInterceptor) .build() } @OtherInterceptorOkHttpClient @Provides fun provideOtherInterceptorOkHttpClient( otherInterceptor: OtherInterceptor ): OkHttpClient { return OkHttpClient.Builder() .addInterceptor(otherInterceptor) .build() } }
Java
@Module @InstallIn(ActivityComponent.class) public class NetworkModule { @AuthInterceptorOkHttpClient @Provides public static OkHttpClient provideAuthInterceptorOkHttpClient( AuthInterceptor authInterceptor ) { return new OkHttpClient.Builder() .addInterceptor(authInterceptor) .build(); } @OtherInterceptorOkHttpClient @Provides public static OkHttpClient provideOtherInterceptorOkHttpClient( OtherInterceptor otherInterceptor ) { return new OkHttpClient.Builder() .addInterceptor(otherInterceptor) .build(); } }
Sie können den gewünschten Typ einfügen, indem Sie das Feld oder den Parameter mit dem entsprechenden Qualifier annotieren:
Kotlin
// As a dependency of another class. @Module @InstallIn(ActivityComponent::class) object AnalyticsModule { @Provides fun provideAnalyticsService( @AuthInterceptorOkHttpClient okHttpClient: OkHttpClient ): AnalyticsService { return Retrofit.Builder() .baseUrl("https://example.com") .client(okHttpClient) .build() .create(AnalyticsService::class.java) } } // As a dependency of a constructor-injected class. class ExampleServiceImpl @Inject constructor( @AuthInterceptorOkHttpClient private val okHttpClient: OkHttpClient ) : ... // At field injection. @AndroidEntryPoint class ExampleActivity: AppCompatActivity() { @AuthInterceptorOkHttpClient @Inject lateinit var okHttpClient: OkHttpClient }
Java
// As a dependency of another class. @Module @InstallIn(ActivityComponent.class) public class AnalyticsModule { @Provides public static AnalyticsService provideAnalyticsService( @AuthInterceptorOkHttpClient OkHttpClient okHttpClient ) { return new Retrofit.Builder() .baseUrl("https://example.com") .client(okHttpClient) .build() .create(AnalyticsService.class); } } // As a dependency of a constructor-injected class. public class ExampleServiceImpl ... { private final OkHttpClient okHttpClient; @Inject ExampleServiceImpl(@AuthInterceptorOkHttpClient OkHttpClient okHttpClient) { this.okHttpClient = okHttpClient; } } // At field injection. @AndroidEntryPoint public class ExampleActivity extends AppCompatActivity { @AuthInterceptorOkHttpClient @Inject OkHttpClient okHttpClient; ... }
Wenn Sie einem Typ einen Qualifier hinzufügen, sollten Sie dies für alle möglichen Möglichkeiten tun, diese Abhängigkeit anzugeben. Wenn Sie die Basis- oder gemeinsame Implementierung ohne einen Qualifier lassen, ist das fehleranfällig und kann dazu führen, dass Hilt die falsche Abhängigkeit einschleust.
Vordefinierte Qualifizierer in Hilt
Hilt bietet einige vordefinierte Qualifikationen. Da Sie die Klasse Context
beispielsweise entweder aus der Anwendung oder aus der Aktivität benötigen können, bietet Hilt die Qualifikanten @ApplicationContext
und @ActivityContext
.
Angenommen, die AnalyticsAdapter
-Klasse aus dem Beispiel benötigt den Kontext der Aktivität. Im folgenden Code wird gezeigt, wie der Aktivitätskontext für AnalyticsAdapter
bereitgestellt wird:
Kotlin
class AnalyticsAdapter @Inject constructor( @ActivityContext private val context: Context, private val service: AnalyticsService ) { ... }
Java
public class AnalyticsAdapter { private final Context context; private final AnalyticsService service; @Inject AnalyticsAdapter( @ActivityContext Context context, AnalyticsService service ) { this.context = context; this.service = service; } }
Weitere vordefinierte Bindungen in Hilt finden Sie unter Standardbindungen für Komponenten.
Generierte Komponenten für Android-Klassen
Für jede Android-Klasse, in der Sie eine Feldinjektion ausführen können, gibt es eine zugehörige Hilt-Komponente, auf die Sie in der @InstallIn
-Anmerkung verweisen können.
Jede Hilt-Komponente ist dafür verantwortlich, ihre Bindungen in die entsprechende Android-Klasse einzuschleusen.
In den vorherigen Beispielen wurde die Verwendung von ActivityComponent
in Hilt-Modulen veranschaulicht.
Hilt bietet die folgenden Komponenten:
Hilt-Komponente | Injektor für |
---|---|
SingletonComponent |
Application |
ActivityRetainedComponent |
– |
ViewModelComponent |
ViewModel |
ActivityComponent |
Activity |
FragmentComponent |
Fragment |
ViewComponent |
View |
ViewWithFragmentComponent |
View mit @WithFragmentBindings kommentiert |
ServiceComponent |
Service |
Lebensdauer von Komponenten
Hilt erstellt und zerstört automatisch Instanzen generierter Komponentenklassen gemäß dem Lebenszyklus der entsprechenden Android-Klassen.
Generierte Komponente | Erstellt um | Gelöscht am |
---|---|---|
SingletonComponent |
Application#onCreate() |
Application vernichtet |
ActivityRetainedComponent |
Activity#onCreate() |
Activity#onDestroy() |
ViewModelComponent |
ViewModel erstellt |
ViewModel zerstört |
ActivityComponent |
Activity#onCreate() |
Activity#onDestroy() |
FragmentComponent |
Fragment#onAttach() |
Fragment#onDestroy() |
ViewComponent |
View#super() |
View zerstört |
ViewWithFragmentComponent |
View#super() |
View zerstört |
ServiceComponent |
Service#onCreate() |
Service#onDestroy() |
Komponentenbereiche
Standardmäßig sind alle Bindungen in Hilt nicht begrenzt. Das bedeutet, dass jedes Mal, wenn Ihre App die Bindung anfordert, Hilt eine neue Instanz des erforderlichen Typs erstellt.
Im Beispiel stellt Hilt jedes Mal, wenn AnalyticsAdapter
als Abhängigkeit für einen anderen Typ oder durch Feldinjektion (wie in ExampleActivity
) bereitgestellt wird, eine neue Instanz von AnalyticsAdapter
bereit.
Mit Hilt können Sie eine Bindung jedoch auch auf eine bestimmte Komponente beschränken. Hilt erstellt eine bereichsbezogene Bindung nur einmal pro Instanz der Komponente, auf die die Bindung beschränkt ist. Alle Anfragen für diese Bindung teilen sich dieselbe Instanz.
In der folgenden Tabelle sind die Bereichsanmerkungen für jede generierte Komponente aufgeführt:
Android-Klasse | Generierte Komponente | Aufgabenstellung |
---|---|---|
Application |
SingletonComponent |
@Singleton |
Activity |
ActivityRetainedComponent |
@ActivityRetainedScoped |
ViewModel |
ViewModelComponent |
@ViewModelScoped |
Activity |
ActivityComponent |
@ActivityScoped |
Fragment |
FragmentComponent |
@FragmentScoped |
View |
ViewComponent |
@ViewScoped |
View mit @WithFragmentBindings kommentiert |
ViewWithFragmentComponent |
@ViewScoped |
Service |
ServiceComponent |
@ServiceScoped |
Wenn Sie im Beispiel AnalyticsAdapter
mithilfe von @ActivityScoped
auf ActivityComponent
beschränken, stellt Hilt während der gesamten Lebensdauer der entsprechenden Aktivität dieselbe Instanz von AnalyticsAdapter
bereit:
Kotlin
@ActivityScoped class AnalyticsAdapter @Inject constructor( private val service: AnalyticsService ) { ... }
Java
@ActivityScoped public class AnalyticsAdapter { private final AnalyticsService service; @Inject AnalyticsAdapter(AnalyticsService service) { this.service = service; } ... }
Angenommen, AnalyticsService
hat einen internen Status, für den immer dieselbe Instanz verwendet werden muss – nicht nur in ExampleActivity
, sondern überall in der App. In diesem Fall ist es sinnvoll, AnalyticsService
auf die SingletonComponent
auszuweiten. Das Ergebnis ist, dass die Komponente immer dieselbe Instanz von AnalyticsService
bereitstellt, wenn sie eine Instanz von AnalyticsService
bereitstellen muss.
Das folgende Beispiel zeigt, wie Sie eine Bindung auf eine Komponente in einem Hilt-Modul beschränken. Der Gültigkeitsbereich einer Bindung muss mit dem Gültigkeitsbereich der Komponente übereinstimmen, in der sie installiert ist. In diesem Beispiel müssen Sie AnalyticsService
also in SingletonComponent
anstelle von ActivityComponent
installieren:
Kotlin
// If AnalyticsService is an interface. @Module @InstallIn(SingletonComponent::class) abstract class AnalyticsModule { @Singleton @Binds abstract fun bindAnalyticsService( analyticsServiceImpl: AnalyticsServiceImpl ): AnalyticsService } // If you don't own AnalyticsService. @Module @InstallIn(SingletonComponent::class) object AnalyticsModule { @Singleton @Provides fun provideAnalyticsService(): AnalyticsService { return Retrofit.Builder() .baseUrl("https://example.com") .build() .create(AnalyticsService::class.java) } }
Java
// If AnalyticsService is an interface. @Module @InstallIn(SingletonComponent.class) public abstract class AnalyticsModule { @Singleton @Binds public abstract AnalyticsService bindAnalyticsService( AnalyticsServiceImpl analyticsServiceImpl ); } // If you don't own AnalyticsService. @Module @InstallIn(SingletonComponent.class) public class AnalyticsModule { @Singleton @Provides public static AnalyticsService provideAnalyticsService() { return new Retrofit.Builder() .baseUrl("https://example.com") .build() .create(AnalyticsService.class); } }
Weitere Informationen zu Hilt-Komponentenbereichen finden Sie unter Bereiche in Android und Hilt.
Komponentenhierarchie
Wenn Sie ein Modul in einer Komponente installieren, können seine Bindungen als Abhängigkeit anderer Bindungen in dieser Komponente oder in einer untergeordneten Komponente in der Komponentenhierarchie verwendet werden:
Standardbindungen für Komponenten
Jede Hilt-Komponente enthält eine Reihe von Standardbindungen, die Hilt als Abhängigkeiten in Ihre eigenen benutzerdefinierten Bindungen einschleusen kann. Beachten Sie, dass diese Bindungen den allgemeinen Aktivitäts- und Fragmenttypen entsprechen und nicht einer bestimmten Unterklasse. Das liegt daran, dass Hilt eine einzelne Aktivitätskomponentendefinition verwendet, um alle Aktivitäten einzuschleusen. Jede Aktivität hat eine andere Instanz dieser Komponente.
Android-Komponente | Standardbindungen |
---|---|
SingletonComponent |
Application |
ActivityRetainedComponent |
Application |
ViewModelComponent |
SavedStateHandle |
ActivityComponent |
Application , Activity |
FragmentComponent |
Application , Activity , Fragment |
ViewComponent |
Application , Activity , View |
ViewWithFragmentComponent |
Application , Activity , Fragment , View |
ServiceComponent |
Application , Service |
Die Bindung an den Anwendungskontext ist auch mit @ApplicationContext
verfügbar.
Beispiel:
Kotlin
class AnalyticsServiceImpl @Inject constructor( @ApplicationContext context: Context ) : AnalyticsService { ... } // The Application binding is available without qualifiers. class AnalyticsServiceImpl @Inject constructor( application: Application ) : AnalyticsService { ... }
Java
public class AnalyticsServiceImpl implements AnalyticsService { private final Context context; @Inject AnalyticsAdapter(@ApplicationContext Context context) { this.context = context; } } // The Application binding is available without qualifiers. public class AnalyticsServiceImpl implements AnalyticsService { private final Application application; @Inject AnalyticsAdapter(Application application) { this.application = application; } }
Die Aktivitätskontextbindung ist auch mit @ActivityContext
verfügbar. Beispiel:
Kotlin
class AnalyticsAdapter @Inject constructor( @ActivityContext context: Context ) { ... } // The Activity binding is available without qualifiers. class AnalyticsAdapter @Inject constructor( activity: FragmentActivity ) { ... }
Java
public class AnalyticsAdapter { private final Context context; @Inject AnalyticsAdapter(@ActivityContext Context context) { this.context = context; } } // The Activity binding is available without qualifiers. public class AnalyticsAdapter { private final FragmentActivity activity; @Inject AnalyticsAdapter(FragmentActivity activity) { this.activity = activity; } }
Abhängigkeiten in Klassen einschleusen, die von Hilt nicht unterstützt werden
Hilt unterstützt die gängigsten Android-Klassen. Möglicherweise müssen Sie jedoch Feldinjektion in Klassen ausführen, die von Hilt nicht unterstützt werden.
In diesen Fällen können Sie mit der Anmerkung @EntryPoint
einen Einstiegspunkt erstellen. Ein Einstiegspunkt ist die Grenze zwischen Code, der von Hilt verwaltet wird, und Code, der nicht von Hilt verwaltet wird. An diesem Punkt tritt Code zum ersten Mal in den Graphen der Objekte ein, die von Hilt verwaltet werden. Über Einstiegspunkte kann Hilt Code verwenden, für den Hilt keine Abhängigkeiten im Abhängigkeitsgraphen bereitstellen kann.
Hilt unterstützt beispielsweise keine Inhaltsanbieter direkt. Wenn ein Inhaltsanbieter Hilt verwenden soll, um einige Abhängigkeiten zu erhalten, müssen Sie für jeden gewünschten Bindungstyp eine Schnittstelle definieren, die mit @EntryPoint
annotiert ist, und Qualifikationen angeben. Fügen Sie dann @InstallIn
hinzu, um die Komponente anzugeben, in der der Einstiegspunkt installiert werden soll:
Kotlin
class ExampleContentProvider : ContentProvider() { @EntryPoint @InstallIn(SingletonComponent::class) interface ExampleContentProviderEntryPoint { fun analyticsService(): AnalyticsService } ... }
Java
public class ExampleContentProvider extends ContentProvider { @EntryPoint @InstallIn(SingletonComponent.class) interface ExampleContentProviderEntryPoint { public AnalyticsService analyticsService(); } ... }
Verwenden Sie die entsprechende statische Methode von EntryPointAccessors
, um auf einen Einstiegspunkt zuzugreifen. Der Parameter sollte entweder die Komponenteninstanz oder das @AndroidEntryPoint
-Objekt sein, das als Komponentenhalter dient. Achten Sie darauf, dass die Komponente, die Sie als Parameter übergeben, und die statische EntryPointAccessors
-Methode mit der Android-Klasse in der @InstallIn
-Anmerkung auf der @EntryPoint
-Benutzeroberfläche übereinstimmen:
Kotlin
class ExampleContentProvider: ContentProvider() { ... override fun query(...): Cursor { val appContext = context?.applicationContext ?: throw IllegalStateException() val hiltEntryPoint = EntryPointAccessors.fromApplication(appContext, ExampleContentProviderEntryPoint::class.java) val analyticsService = hiltEntryPoint.analyticsService() ... } }
Java
public class ExampleContentProvider extends ContentProvider { @Override public Cursor query(...) { Context appContext = getContext().getApplicationContext(); ExampleContentProviderEntryPoint hiltEntryPoint = EntryPointAccessors.fromApplication(appContext, ExampleContentProviderEntryPoint.class); AnalyticsService analyticsService = hiltEntryPoint.analyticsService(); } }
In diesem Beispiel müssen Sie ApplicationContext
verwenden, um den Einstiegspunkt abzurufen, da er in SingletonComponent
installiert ist. Wenn sich die Bindung, die Sie abrufen möchten, in der ActivityComponent
befindet, verwenden Sie stattdessen die ActivityContext
.
Hilt and Dagger
Hilt basiert auf der Dagger-Bibliothek zur Abhängigkeitsinjektion und bietet eine Standardmethode, um Dagger in eine Android-Anwendung einzubinden.
Im Vergleich zu Dagger hat Hilt folgende Ziele:
- Vereinfachung der Dagger-bezogenen Infrastruktur für Android-Apps
- Sie können einen Standardsatz von Komponenten und Bereichen erstellen, um die Einrichtung, Lesbarkeit und Codefreigabe zwischen Apps zu vereinfachen.
- Sie können damit ganz einfach verschiedene Bindungen für verschiedene Buildtypen bereitstellen, z. B. für Tests, Debugging oder Releases.
Da das Android-Betriebssystem viele seiner eigenen Framework-Klassen instanziiert, müssen Sie bei der Verwendung von Dagger in einer Android-App eine beträchtliche Menge an Boilerplate-Code schreiben. Hilt reduziert den Boilerplate-Code, der bei der Verwendung von Dagger in einer Android-Anwendung erforderlich ist. Hilt generiert und stellt Folgendes automatisch bereit:
- Komponenten zum Integrieren von Android-Framework-Klassen in Dagger, die Sie sonst manuell erstellen müssten.
- Bereichsanmerkungen, die mit den Komponenten verwendet werden, die Hilt automatisch generiert.
- Vordefinierte Bindungen zur Darstellung von Android-Klassen wie
Application
oderActivity
. - Vordefinierte Modifikatoren für
@ApplicationContext
und@ActivityContext
Dagger- und Hilt-Code können in derselben Codebasis nebeneinander existieren. In den meisten Fällen ist es jedoch am besten, Hilt zu verwenden, um die gesamte Verwendung von Dagger unter Android zu verwalten. Informationen zum Migrieren eines Projekts, in dem Dagger verwendet wird, zu Hilt finden Sie im Migrationsleitfaden und im Codelab zur Migration Ihrer Dagger-Anwendung zu Hilt.
Weitere Informationen
Weitere Informationen zu Hilt finden Sie in den folgenden zusätzlichen Ressourcen.
Produktproben
Codelabs
Blogs
- Dependency Injection unter Android mit Hilt
- Scoping in Android und Hilt
- Komponenten zur Hilt-Hierarchie hinzufügen
- Google I/O-App zu Hilt migrieren