Hilt ist eine Abhängigkeitsinjektionsbibliothek für Android, die den Standard für die manuelle Abhängigkeitsinjektion in Ihrem Projekt reduziert. Bei einer 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. Es stellt Container für jede Android-Klasse in Ihrem Projekt bereit und verwaltet deren Lebenszyklen automatisch. Hilt baut auf der beliebten DI-Bibliothek Dagger auf und profitiert dadurch von der Richtigkeit bei Kompilierungszeit, Laufzeitleistung, Skalierbarkeit und Android Studio-Unterstützung, die Dagger bietet. Weitere Informationen finden Sie unter Hilt und Dagger.
In diesem Leitfaden werden die grundlegenden Konzepte von Hilt und die zugehörigen Container erläutert. Außerdem wird gezeigt, wie eine vorhandene App für die Verwendung von Hilt Bootstrapping ausführen kann.
Abhängigkeiten hinzufügen
Fügen Sie zuerst das Plug-in hilt-android-gradle-plugin
in die Stammdatei build.gradle
Ihres Projekts ein:
Cool
plugins { ... id 'com.google.dagger.hilt.android' version '2.44' apply false }
Kotlin
plugins { ... id("com.google.dagger.hilt.android") version "2.44" apply false }
Wenden Sie dann das Gradle-Plug-in an und fügen Sie diese Abhängigkeiten in die Datei app/build.gradle
ein:
Cool
... plugins { id 'kotlin-kapt' id 'com.google.dagger.hilt.android' } android { ... } dependencies { implementation "com.google.dagger:hilt-android:2.44" kapt "com.google.dagger:hilt-compiler:2.44" } // 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.44") kapt("com.google.dagger:hilt-android-compiler:2.44") } // Allow references to generated code kapt { correctErrorTypes = true }
Hilt verwendet Java 8-Funktionen. Fügen Sie der Datei app/build.gradle
Folgendes hinzu, um Java 8 in Ihrem Projekt zu aktivieren:
Cool
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 wird an den Lebenszyklus des Application
-Objekts angehängt und stellt Abhängigkeiten bereit. Darüber hinaus ist sie die übergeordnete Komponente der Anwendung. Das bedeutet, dass andere Komponenten auf die von ihr bereitgestellten Abhängigkeiten zugreifen können.
Abhängigkeiten in Android-Klassen einfügen
Sobald Hilt in Ihrer Application
-Klasse eingerichtet ist und eine Komponente auf Anwendungsebene verfügbar ist, kann Hilt Abhängigkeiten für andere Android-Klassen mit der Annotation @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 davon abhängige Android-Klassen annotieren. Wenn Sie beispielsweise ein Fragment annotieren, müssen Sie auch alle Aktivitäten annotieren, in denen Sie dieses Fragment verwenden.
@AndroidEntryPoint
generiert für jede Android-Klasse in Ihrem Projekt eine eigene Hilt-Komponente. Diese Komponenten können Abhängigkeiten von ihren jeweiligen übergeordneten Klassen empfangen, wie unter Komponentenhierarchie beschrieben.
Um Abhängigkeiten von einer Komponente abzurufen, verwenden Sie die Annotation @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 Injektion verwenden.
Diese Klassen benötigen die Annotation @AndroidEntryPoint
nicht, wenn sie abstrakt sind.
Weitere Informationen darüber, in welchen Lebenszyklus-Callback eine Android-Klasse eingeschleust 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 bereitzustellen, ist die Konstruktoreinschleusung. Mit der Annotation @Inject
für den Konstruktor einer Klasse teilen Sie Hilt mit, 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 annotierten Konstruktors einer Klasse sind die Abhängigkeiten dieser Klasse. Im 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 in den Konstruktor eingefügt werden. Dies kann verschiedene Gründe haben. Sie können beispielsweise keine Schnittstelle mit dem Konstruktor injizieren. Sie können auch keinen Typ konstruktor injizieren, der Ihnen nicht gehört, z. B. eine Klasse aus einer externen Bibliothek. In diesen Fällen können Sie Hilt mithilfe von Hilt-Modulen Bindungsinformationen bereitstellen.
Ein Hilt-Modul ist eine Klasse, die mit @Module
annotiert ist. Wie bei einem Dagger-Modul wird Hilt darüber informiert, wie Instanzen bestimmter Typen bereitgestellt werden. Im Gegensatz zu Dagger-Modulen müssen Sie Hilt-Module mit @InstallIn
annotieren, um Hilt mitzuteilen, in welcher Android-Klasse die einzelnen Module verwendet oder installiert werden sollen.
Abhängigkeiten, die Sie in Hilt-Modulen angeben, sind in allen generierten Komponenten verfügbar, die der Android-Klasse zugeordnet sind, in der Sie das Hilt-Modul installieren.
Schnittstelleninstanzen mit @Binds einschleusen
Sehen Sie sich das Beispiel AnalyticsService
an. Wenn AnalyticsService
eine Schnittstelle ist, kann sie nicht durch den Konstruktor eingefügt werden. Stellen Sie stattdessen Hilt die Bindungsinformationen bereit, indem Sie eine abstrakte Funktion erstellen, die in einem Hilt-Modul mit @Binds
annotiert ist.
Die Annotation @Binds
teilt Hilt mit, welche Implementierung verwendet werden soll, wenn eine Instanz einer Schnittstelle bereitgestellt werden muss.
Die annotierte Funktion stellt Hilt die folgenden Informationen zur Verfügung:
- Der Rückgabetyp der Funktion gibt Hilt an, für welche Schnittstelle die Funktion Instanzen bereitstellt.
- Der Funktionsparameter teilt Hilt mit, 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, da Hilt diese Abhängigkeit in ExampleActivity
einfügen soll. Diese Anmerkung bedeutet, dass alle Abhängigkeiten in AnalyticsModule
in allen Aktivitäten der App verfügbar sind.
Instanzen mit @Provides einfügen
Schnittstellen sind nicht der einzige Fall, bei dem Sie einen Typ nicht konstruktor einschleusen können.
Das Einschleusen von Konstruktoren ist auch nicht möglich, wenn Sie nicht der Inhaber der Klasse sind, da sie aus einer externen Bibliothek (Klassen wie Retrofit, OkHttpClient
oder Raumdatenbanken) stammt oder wenn Instanzen mit dem Builder-Muster erstellt werden müssen.
Betrachten Sie das vorherige Beispiel. Wenn Sie nicht der Inhaber der AnalyticsService
-Klasse sind, können Sie Hilt anweisen, wie Instanzen dieses Typs bereitgestellt werden sollen. Dazu erstellen Sie eine Funktion in einem Hilt-Modul und versehen diese Funktion mit @Provides
.
Die annotierte Funktion stellt Hilt die folgenden Informationen bereit:
- Der Rückgabetyp der Funktion gibt Hilt an, von welchem Typ die Funktion Instanzen bereitstellt.
- Die Funktionsparameter informieren Hilt über die Abhängigkeiten des entsprechenden Typs.
- Der Funktionstext teilt Hilt mit, wie eine Instanz des entsprechenden Typs bereitgestellt werden soll. Hilt führt den Funktionstext 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 verschiedene Implementierungen desselben Typs als Abhängigkeiten bereitstellen soll, müssen Sie Hilt mehrere Bindungen bereitstellen. Mit Qualifier können Sie mehrere Bindungen für denselben Typ definieren.
Ein Qualifier ist eine Annotation, mit der Sie eine bestimmte Bindung für einen Typ identifizieren, wenn für diesen Typ mehrere Bindungen definiert sind.
Betrachten Sie das Beispiel. Wenn Sie Aufrufe von AnalyticsService
abfangen müssen, können Sie ein OkHttpClient
-Objekt mit einem Abfangende verwenden. Bei anderen Diensten müssen Sie Aufrufe möglicherweise anders abfangen. In diesem Fall musst du Hilt mitteilen, wie zwei verschiedene Implementierungen von OkHttpClient
zur Verfügung gestellt werden sollen.
Definieren Sie zuerst die Qualifizierer, mit denen Sie die Methoden @Binds
oder @Provides
annotieren:
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 dem jeweiligen Qualifizierer entspricht. In diesem Fall könnten Sie ein Hilt-Modul mit @Provides
verwenden.
Beide Methoden haben denselben Rückgabetyp, werden aber von den Qualifizierern als zwei verschiedene Bindungen gekennzeichnet:
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 spezifischen Typ einfügen, den Sie benötigen, 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 Qualifizierer hinzufügen, sollten Sie als Best Practice allen Möglichkeiten zum Bereitstellen dieser Abhängigkeit Qualifizierer hinzufügen. Wenn die Basis- oder gängige Implementierung ohne Qualifier verwendet wird, ist dies fehleranfällig und kann dazu führen, dass Hilt die falsche Abhängigkeit einschleust.
Vordefinierte Kennzeichner in Hilt
Hilt bietet einige vordefinierte Qualifier. Da Sie beispielsweise die Klasse Context
entweder aus der Anwendung oder der Aktivität benötigen, stellt Hilt die Qualifizierer @ApplicationContext
und @ActivityContext
bereit.
Angenommen, die Klasse AnalyticsAdapter
aus dem Beispiel benötigt den Kontext der Aktivität. Im folgenden Code sehen Sie, 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; } }
Informationen zu weiteren vordefinierten Bindungen, die in Hilt verfügbar sind, finden Sie unter Standardbindungen für Komponenten.
Generierte Komponenten für Android-Klassen
Für jede Android-Klasse, in der Sie Feldeinschleusungen durchführen können, gibt es eine zugehörige Hilt-Komponente, auf die Sie in der Annotation @InstallIn
verweisen können.
Jede Hilt-Komponente ist für das Einfügen ihrer Bindungen in die entsprechende Android-Klasse verantwortlich.
In den vorherigen Beispielen wurde die Verwendung von ActivityComponent
in Hilt-Modulen demonstriert.
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 annotiert |
ServiceComponent |
Service |
Lebensdauer von Komponenten
Hilt erstellt und löscht automatisch Instanzen generierter Komponentenklassen nach dem Lebenszyklus der entsprechenden Android-Klassen.
Generierte Komponente | Erstellt um | Gelöscht um |
---|---|---|
SingletonComponent |
Application#onCreate() |
Application gelöscht |
ActivityRetainedComponent |
Activity#onCreate() |
Activity#onDestroy() |
ViewModelComponent |
ViewModel erstellt |
ViewModel gelöscht |
ActivityComponent |
Activity#onCreate() |
Activity#onDestroy() |
FragmentComponent |
Fragment#onAttach() |
Fragment#onDestroy() |
ViewComponent |
View#super() |
View gelöscht |
ViewWithFragmentComponent |
View#super() |
View gelöscht |
ServiceComponent |
Service#onCreate() |
Service#onDestroy() |
Komponentenbereiche
Standardmäßig sind alle Bindungen in Hilt ohne Geltungsbereich. Das bedeutet, dass Hilt jedes Mal, wenn Ihre Anwendung die Bindung anfordert, eine neue Instanz des erforderlichen Typs erstellt.
In diesem Beispiel stellt Hilt jedes Mal, wenn Hilt AnalyticsAdapter
als Abhängigkeit zu einem anderen Typ oder durch Feldeinschleusung (wie bei ExampleActivity
) bereitstellt, eine neue Instanz von AnalyticsAdapter
bereit.
Mit Hilt kann eine Bindung jedoch auch auf eine bestimmte Komponente beschränkt werden. Mit Hilt wird eine auf einen Bereich reduzierte Bindung nur einmal pro Instanz der Komponente erstellt, auf die die Bindung beschränkt ist. Alle Anfragen für diese Bindung teilen sich dieselbe Instanz.
In der folgenden Tabelle sind die Annotationen zum Umfang für jede generierte Komponente aufgeführt:
Android-Kurs | Generierte Komponente | Aufgabenstellung |
---|---|---|
Application |
SingletonComponent |
@Singleton |
Activity |
ActivityRetainedComponent |
@ActivityRetainedScoped |
ViewModel |
ViewModelComponent |
@ViewModelScoped |
Activity |
ActivityComponent |
@ActivityScoped |
Fragment |
FragmentComponent |
@FragmentScoped |
View |
ViewComponent |
@ViewScoped |
View mit @WithFragmentBindings annotiert |
ViewWithFragmentComponent |
@ViewScoped |
Service |
ServiceComponent |
@ServiceScoped |
Wenn Sie im Beispiel AnalyticsAdapter
mit @ActivityScoped
auf die ActivityComponent
festlegen, 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, bei dem jedes Mal dieselbe Instanz verwendet werden muss – nicht nur in ExampleActivity
, sondern überall in der Anwendung. In diesem Fall ist es sinnvoll, AnalyticsService
auf SingletonComponent
zu legen. Dadurch wird jedes Mal, wenn die Komponente eine Instanz von AnalyticsService
bereitstellen muss, dieselbe Instanz bereitgestellt.
Das folgende Beispiel zeigt, wie eine Bindung auf eine Komponente in einem Hilt-Modul festgelegt wird. Der Bereich einer Bindung muss mit dem Bereich der Komponente übereinstimmen, in der sie installiert ist. In diesem Beispiel müssen Sie also AnalyticsService
in SingletonComponent
statt 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 den Bereichen von Hilt-Komponenten finden Sie unter Umfang in Android und Hilt festlegen.
Komponentenhierarchie
Wenn Sie ein Modul in einer Komponente installieren, kann auf seine Bindungen in Abhängigkeit von anderen Bindungen in dieser Komponente oder in einer ihr untergeordneten Komponente in der Komponentenhierarchie zugegriffen werden:
Standardbindungen für Komponenten
Jede Hilt-Komponente enthält eine Reihe von Standardbindungen, die Hilt als Abhängigkeiten in Ihre eigenen benutzerdefinierten Bindungen einfügen kann. Beachten Sie, dass diese Bindungen den allgemeinen Aktivitäts- und Fragmenttypen und nicht einer bestimmten abgeleiteten Klasse entsprechen. 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 Kontextbindung der Anwendung 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 einfügen, die von Hilt nicht unterstützt werden
Hilt unterstützt die gängigsten Android-Klassen. Möglicherweise müssen Sie jedoch Felder in Klassen einfügen, die von Hilt nicht unterstützt werden.
In diesen Fällen können Sie mit der Annotation @EntryPoint
einen Einstiegspunkt erstellen. Ein Einstiegspunkt ist die Grenze zwischen dem von Hilt verwalteten Code und dem Code, der nicht verwaltet wird. Dies ist der Punkt, an dem Code zum ersten Mal in die von Hilt verwaltete Objektgrafik eingegeben wird. Einstiegspunkte ermöglichen es Hilt, Code zu verwenden, den Hilt nicht verwaltet, um Abhängigkeiten innerhalb des Abhängigkeitsdiagramms bereitzustellen.
Hilt unterstützt beispielsweise Contentanbieter nicht direkt. Wenn ein Contentanbieter mithilfe von Hilt einige Abhängigkeiten abrufen soll, müssen Sie eine Schnittstelle definieren, die für jeden gewünschten Bindungstyp mit @EntryPoint
annotiert ist und Qualifizierer enthält. 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 Objekt @AndroidEntryPoint
sein, das als Komponenteninhaber fungiert. Die Komponente, die Sie als Parameter übergeben, und die statische Methode EntryPointAccessors
müssen beide der Android-Klasse in der Annotation @InstallIn
auf der @EntryPoint
-Oberfläche entsprechen:
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
zum Abrufen des Einstiegspunkts verwenden, da der Einstiegspunkt in SingletonComponent
installiert ist. Wenn sich die Bindung, die Sie abrufen möchten, im ActivityComponent
befindet, verwenden Sie stattdessen ActivityContext
.
Griff und Dolch
Hilt basiert auf der Dagger-Abhängigkeitsinjektionsbibliothek und bietet eine standardmäßige Möglichkeit zur Integration von Dagger in eine Android-App.
In Bezug auf Dagger verfolgt Hilt folgende Ziele:
- Vereinfachung der Dagger-bezogenen Infrastruktur für Android-Apps
- Zum Erstellen eines Standardsatzes von Komponenten und Bereichen, um die Einrichtung, Lesbarkeit und Codefreigabe zwischen Anwendungen zu vereinfachen.
- Eine einfache Möglichkeit, verschiedene Bindungen für verschiedene Build-Typen bereitzustellen, z. B. für Tests, Fehlerbehebung oder Releases.
Da das Android-Betriebssystem viele seiner eigenen Framework-Klassen instanziiert, müssen Sie bei der Verwendung von Dagger in einer Android-App viel Textbausteine schreiben. Hilt reduziert den Boilerplate-Code, der für die Verwendung von Dagger in einer Android-Anwendung erforderlich ist. Hilt generiert automatisch Folgendes:
- Komponenten für die Integration von Android-Framework-Klassen in Dagger, die Sie sonst manuell erstellen müssten.
- Bereichsanmerkungen zur Verwendung mit den Komponenten, die Hilt automatisch generiert.
- Vordefinierte Bindungen zur Darstellung von Android-Klassen wie
Application
oderActivity
. - Vordefinierte Qualifizierer zur Darstellung von
@ApplicationContext
und@ActivityContext
.
Dagger- und Hilt-Code können in derselben Codebasis nebeneinander bestehen. In den meisten Fällen empfiehlt es sich jedoch, mit Hilt die gesamte Nutzung von Dagger unter Android zu verwalten. Informationen zum Migrieren eines Projekts, in dem Dagger verwendet wird, finden Sie im Migrationsleitfaden und im Codelab zum Migrieren der Dagger-Anwendung zu Hilt.
Zusätzliche Ressourcen
Weitere Informationen zu Hilt finden Sie in den folgenden zusätzlichen Ressourcen.
Produktproben
Codelabs
Blogs
- Abhängigkeitsinjektion unter Android mit Hilt
- Umfang in Android und Hilt
- Komponenten zur Hilt-Hierarchie hinzufügen
- Google I/O-Anwendung zu Hit migrieren