Hilt est une bibliothèque d'injection de dépendances pour Android qui réduit le code récurrent nécessaire pour injecter manuellement des dépendances dans votre projet. L'injection manuelle de dépendances nécessite de créer chaque classe et ses dépendances manuellement, ainsi que d'utiliser des conteneurs pour réutiliser et gérer les dépendances.
Hilt offre une méthode standard pour utiliser l'injection de dépendances dans votre application en fournissant des conteneurs pour chaque classe Android de votre projet et en gérant automatiquement leur cycle de vie. Hilt repose sur Dagger, une bibliothèque d'injection de dépendances courante, et bénéficie ainsi de l'exactitude du temps de compilation, des performances d'exécution, de l'évolutivité et de la compatibilité avec Android Studio qu'offre Dagger. Pour en savoir plus, consultez la section Hilt et Dagger.
Ce guide décrit les concepts de base de Hilt et de ses conteneurs générés. Il comprend également une démonstration de l'amorçage d'une application existante pour utiliser Hilt.
Ajouter des dépendances
Tout d'abord, ajoutez le plug-in hilt-android-gradle-plugin
au fichier build.gradle
racine de votre projet :
Groovy
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 }
Ensuite, appliquez le plug-in Gradle et ajoutez ces dépendances dans votre fichier app/build.gradle
:
Groovy
... 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 utilise les fonctionnalités de Java 8. Pour activer Java 8 dans votre projet, ajoutez les éléments suivants au fichier app/build.gradle
:
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 } }
Classe d'application Hilt
Toutes les applications qui utilisent Hilt doivent contenir une classe Application
annotée avec @HiltAndroidApp
.
@HiltAndroidApp
déclenche la génération du code de Hilt, y compris une classe de base de votre application qui sert de conteneur de dépendances au niveau de l'application.
Kotlin
@HiltAndroidApp class ExampleApplication : Application() { ... }
Java
@HiltAndroidApp public class ExampleApplication extends Application { ... }
Ce composant Hilt généré est associé au cycle de vie de l'objet Application
et lui fournit des dépendances. En outre, il s'agit du composant parent de l'application, ce qui signifie que d'autres composants peuvent accéder aux dépendances qu'il fournit.
Injecter des dépendances dans des classes Android
Une fois que Hilt est configuré dans votre classe Application
et qu'un composant au niveau de l'application est disponible, Hilt peut fournir des dépendances à d'autres classes Android comportant l'annotation @AndroidEntryPoint
:
Kotlin
@AndroidEntryPoint class ExampleActivity : AppCompatActivity() { ... }
Java
@AndroidEntryPoint public class ExampleActivity extends AppCompatActivity { ... }
Hilt est actuellement compatible avec les classes Android suivantes :
Application
(en utilisant@HiltAndroidApp
)ViewModel
(en utilisant@HiltViewModel
)Activity
Fragment
View
Service
BroadcastReceiver
Si vous annotez une classe Android avec @AndroidEntryPoint
, vous devez également annoter les classes Android qui en dépendent. Par exemple, si vous annotez un fragment, vous devez également annoter toutes les activités dans lesquelles vous l'utilisez.
@AndroidEntryPoint
génère un composant Hilt individuel pour chaque classe Android de votre projet. Ces composants peuvent recevoir des dépendances provenant de leurs classes parentes respectives, comme décrit dans la section Hiérarchie des composants.
Pour obtenir des dépendances à partir d'un composant, utilisez l'annotation @Inject
pour effectuer une injection de champ :
Kotlin
@AndroidEntryPoint class ExampleActivity : AppCompatActivity() { @Inject lateinit var analytics: AnalyticsAdapter ... }
Java
@AndroidEntryPoint public class ExampleActivity extends AppCompatActivity { @Inject AnalyticsAdapter analytics; ... }
Les classes injectées par Hilt peuvent avoir d'autres classes de base qui utilisent également l'injection.
Ces classes ne nécessitent pas l'annotation @AndroidEntryPoint
si elles sont abstraites.
Pour en savoir plus sur le rappel de cycle de vie auquel une classe Android est injectée, consultez la section Cycles de vie des composants.
Définir les liaisons de Hilt
Pour effectuer l'injection par champs, Hilt doit savoir comment fournir les instances des dépendances nécessaires à partir du composant correspondant. Une liaison contient les informations nécessaires pour fournir des instances d'un type en tant que dépendance.
L'une des méthodes permettant de fournir des informations de liaison à Hilt est l'injection par constructeur. Utilisez l'annotation @Inject
sur le constructeur d'une classe pour indiquer à Hilt comment fournir des instances de cette classe :
Kotlin
class AnalyticsAdapter @Inject constructor( private val service: AnalyticsService ) { ... }
Java
public class AnalyticsAdapter { private final AnalyticsService service; @Inject AnalyticsAdapter(AnalyticsService service) { this.service = service; } ... }
Les paramètres d'un constructeur annoté d'une classe sont les dépendances de cette classe. Dans l'exemple, AnalyticsAdapter
utilise AnalyticsService
comme dépendance. Par conséquent, Hilt doit également savoir comment fournir des instances de AnalyticsService
.
Modules Hilt
Parfois, un constructeur ne peut pas être injecté dans un type. Les raisons peuvent être multiples. Par exemple, vous ne pouvez pas injecter un constructeur dans une interface. Vous ne pouvez pas non plus injecter un constructeur dans un type qui ne vous appartient pas, comme une classe provenant d'une bibliothèque externe. Dans ces cas, vous pouvez fournir des informations de liaison à Hilt à l'aide de modules Hilt.
Un module Hilt est une classe annotée avec @Module
. Tout comme un module Dagger, il indique à Hilt comment fournir des instances de certains types. Contrairement aux modules Dagger, vous devez annoter les modules Hilt avec @InstallIn
pour indiquer à Hilt la classe Android dans laquelle chaque module sera utilisé ou installé.
Les dépendances que vous fournissez dans les modules Hilt sont disponibles dans tous les composants générés associés à la classe Android où vous installez le module Hilt.
Injecter des instances d'interface avec "@Binds"
Prenons l'exemple d'AnalyticsService
. Si AnalyticsService
est une interface, vous ne pouvez pas y injecter un constructeur. Fournissez plutôt les informations de liaison à Hilt en créant une fonction abstraite annotée avec @Binds
dans un module Hilt.
L'annotation @Binds
indique à Hilt l'implémentation à utiliser lorsqu'il doit fournir une instance d'une interface.
La fonction annotée fournit les informations suivantes à Hilt :
- Le type renvoyé de la fonction indique à Hilt l'interface dont la fonction fournit des instances.
- Le paramètre de fonction indique à Hilt l'implémentation à fournir.
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 ); }
Le module Hilt AnalyticsModule
est annoté avec @InstallIn(ActivityComponent.class)
, car vous souhaitez que Hilt injecte cette dépendance dans ExampleActivity
. Cette annotation signifie que toutes les dépendances de AnalyticsModule
sont disponibles dans toutes les activités de l'application.
Injecter des instances avec "@Provides"
Les interfaces ne sont pas le seul cas dans lequel vous ne pouvez pas injecter un constructeur dans un type.
Il est également impossible d'injecter un constructeur si vous ne possédez pas la classe, car elle provient d'une bibliothèque externe (classes comme Retrofit, OkHttpClient
ou les bases de données Room), ou si des instances doivent être créées avec le modèle de compilateur.
Prenons l'exemple précédent. Si vous ne possédez pas directement la classe AnalyticsService
, vous pouvez indiquer à Hilt comment fournir des instances de ce type en créant une fonction dans un module Hilt et en l'annotant avec @Provides
.
La fonction annotée fournit les informations suivantes à Hilt :
- Le type renvoyé de la fonction indique à Hilt le type dont la fonction fournit des instances.
- Les paramètres de la fonction indiquent à Hilt les dépendances du type correspondant.
- Le corps de la fonction indique à Hilt comment fournir une instance du type correspondant. Hilt exécute le corps de la fonction chaque fois qu'il doit fournir une instance de ce type.
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); } }
Fournir plusieurs liaisons pour le même type
Si vous avez besoin que Hilt fournisse différentes implémentations d'un même type en tant que dépendances, vous devez lui fournir plusieurs liaisons. Vous pouvez définir plusieurs liaisons pour le même type à l'aide de qualificatifs.
Un qualificatif est une annotation qui permet d'identifier une liaison spécifique d'un type lorsque plusieurs liaisons sont définies pour ce type.
Prenons cet exemple. Si vous devez intercepter les appels vers AnalyticsService
, vous pouvez utiliser un objet OkHttpClient
avec un intercepteur. Pour les autres services, vous devrez peut-être intercepter les appels d'une autre manière. Dans ce cas, vous devez indiquer à Hilt comment fournir deux implémentations différentes de OkHttpClient
.
Tout d'abord, définissez les qualificatifs que vous utiliserez pour annoter les méthodes @Binds
ou @Provides
:
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 {}
Ensuite, Hilt doit savoir comment fournir une instance du type correspondant à chaque qualificatif. Dans ce cas, vous pouvez utiliser un module Hilt avec @Provides
.
Le type renvoyé est identique pour les deux méthodes, mais les qualificatifs les associent à deux liaisons différentes :
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(); } }
Vous pouvez injecter le type spécifique dont vous avez besoin en annotant le champ ou le paramètre avec le qualificatif correspondant :
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; ... }
Si vous ajoutez un qualificatif à un type, nous vous recommandons d'ajouter des qualificatifs à toutes les méthodes possibles permettant de fournir cette dépendance. Une implémentation de base ou commune sans qualificatif risque d'entraîner des erreurs et pourrait provoquer l'injection d'une mauvaise dépendance par Hilt.
Qualificatifs prédéfinis dans Hilt
Hilt fournit quelques qualificatifs prédéfinis. Par exemple, comme vous aurez peut-être besoin de la classe Context
de l'application ou de l'activité, Hilt fournit les qualificatifs @ApplicationContext
et @ActivityContext
.
Supposons que la classe AnalyticsAdapter
de l'exemple ait besoin du contexte de l'activité. Le code suivant montre comment fournir le contexte de l'activité à AnalyticsAdapter
:
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; } }
Pour les autres liaisons prédéfinies disponibles dans Hilt, consultez la section Liaisons par défaut des composants.
Composants générés pour les classes Android
Pour chaque classe Android dans laquelle vous pouvez effectuer une injection de champ, un composant Hilt associé est disponible dans l'annotation @InstallIn
.
Chaque composant Hilt est chargé d'injecter ses liaisons dans la classe Android correspondante.
Les exemples précédents ont illustré l'utilisation d'ActivityComponent
dans les modules Hilt.
Hilt fournit les composants suivants :
Composant Hilt | Injecteur pour |
---|---|
SingletonComponent |
Application |
ActivityRetainedComponent |
N/A |
ViewModelComponent |
ViewModel |
ActivityComponent |
Activity |
FragmentComponent |
Fragment |
ViewComponent |
View |
ViewWithFragmentComponent |
View annoté avec @WithFragmentBindings |
ServiceComponent |
Service |
Cycles de vie des composants
Hilt crée et détruit automatiquement des instances de classes de composants générés en suivant le cycle de vie des classes Android correspondantes.
Composant généré | Créé dans | Détruit dans |
---|---|---|
SingletonComponent |
Application#onCreate() |
Application détruite |
ActivityRetainedComponent |
Activity#onCreate() |
Activity#onDestroy() |
ViewModelComponent |
ViewModel créé |
ViewModel détruit |
ActivityComponent |
Activity#onCreate() |
Activity#onDestroy() |
FragmentComponent |
Fragment#onAttach() |
Fragment#onDestroy() |
ViewComponent |
View#super() |
View détruite |
ViewWithFragmentComponent |
View#super() |
View détruite |
ServiceComponent |
Service#onCreate() |
Service#onDestroy() |
Champs d'application des composants
Par défaut, toutes les liaisons dans Hilt n'ont pas de champ d'application. Cela signifie que, chaque fois que votre application demande la liaison, Hilt crée une instance du type requis.
Dans l'exemple, chaque fois que Hilt fournit AnalyticsAdapter
en tant que dépendance d'un autre type ou via l'injection par champs (comme dans ExampleActivity
), Hilt fournit une nouvelle instance d'AnalyticsAdapter
.
Toutefois, Hilt permet également de définir le champ d'application d'une liaison sur un composant particulier. Hilt crée un champ d'application de liaison une seule fois par instance du composant sur lequel le champ d'application de liaison est défini. Toutes les demandes pour cette liaison partagent la même instance.
Le tableau ci-dessous indique les annotations de champ d'application pour chaque composant généré :
Classe Android | Composant généré | Champ d'application |
---|---|---|
Application |
SingletonComponent |
@Singleton |
Activity |
ActivityRetainedComponent |
@ActivityRetainedScoped |
ViewModel |
ViewModelComponent |
@ViewModelScoped |
Activity |
ActivityComponent |
@ActivityScoped |
Fragment |
FragmentComponent |
@FragmentScoped |
View |
ViewComponent |
@ViewScoped |
View annoté avec @WithFragmentBindings |
ViewWithFragmentComponent |
@ViewScoped |
Service |
ServiceComponent |
@ServiceScoped |
Dans l'exemple, si vous définissez le champ d'application d'AnalyticsAdapter
sur l'ActivityComponent
à l'aide d'@ActivityScoped
, Hilt fournit la même instance d'AnalyticsAdapter
tout au long du cycle de vie de l'activité correspondante :
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; } ... }
Supposons qu'AnalyticsService
ait un état interne nécessitant que la même instance soit utilisée à chaque fois, non seulement dans ExampleActivity
, mais aussi dans toute l'application. Dans ce cas, il est approprié de définir le champ d'application d'AnalyticsService
sur SingletonComponent
. Par conséquent, lorsque le composant doit fournir une instance d'AnalyticsService
, il fournit la même instance à chaque fois.
L'exemple suivant montre comment définir le champ d'application d'une liaison sur un composant d'un module Hilt. Le champ d'application d'une liaison doit correspondre à celui du composant où elle est installée. Dans cet exemple, vous devez donc installer AnalyticsService
dans SingletonComponent
au lieu d'ActivityComponent
:
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); } }
Pour en savoir plus sur les champs d'application des composants Hilt, consultez la page Définition du champ d'application dans Android et Hilt.
Hiérarchie des composants
L'installation d'un module dans un composant permet d'accéder à ses liaisons en tant que dépendance d'autres liaisons dans ce composant ou dans tout composant enfant inférieur dans la hiérarchie des composants :
Liaisons par défaut des composants
Chaque composant Hilt est fourni avec un ensemble de liaisons par défaut que Hilt peut injecter en tant que dépendances dans vos propres liaisons personnalisées. Notez que ces liaisons correspondent à des types d'activité et de fragments généraux, et non à une sous-classe spécifique. En effet, Hilt utilise une seule définition de composant d'activité pour injecter toutes les activités. Chaque activité est associée à une instance différente de ce composant.
Composant Android | Liaisons par défaut |
---|---|
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 |
La liaison de contexte de l'application est également disponible à l'aide de @ApplicationContext
.
Exemple :
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; } }
La liaison de contexte de l'activité est également disponible à l'aide de @ActivityContext
. Exemple :
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; } }
Injecter des dépendances dans des classes non compatibles avec Hilt
Hilt est compatible avec les classes Android les plus courantes. Cependant, vous devrez peut-être effectuer une injection de champ dans les classes non compatibles avec Hilt.
Dans ces cas, vous pouvez créer un point d'entrée à l'aide de l'annotation @EntryPoint
. Un point d'entrée est la limite entre le code géré par Hilt et le code qui ne l'est pas. Il s'agit du point au niveau duquel le code entre pour la première fois dans le graphique des objets gérés par Hilt. Les points d'entrée permettent à Hilt d'utiliser du code qu'il ne gère pas pour fournir des dépendances dans le graphique de dépendances.
Par exemple, Hilt ne prend pas directement en charge les fournisseurs de contenu. Si vous souhaitez qu'un fournisseur de contenu utilise Hilt pour obtenir des dépendances, vous devez définir une interface annotée avec @EntryPoint
pour chaque type de liaison souhaité et inclure des qualificatifs. Ajoutez ensuite @InstallIn
pour spécifier le composant dans lequel installer le point d'entrée, comme suit :
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(); } ... }
Pour accéder à un point d'entrée, utilisez la méthode statique appropriée depuis EntryPointAccessors
. Le paramètre doit correspondre soit à l'instance du composant, soit à l'objet @AndroidEntryPoint
qui sert de conteneur de composants. Assurez-vous que le composant transmis en tant que paramètre et la méthode statique EntryPointAccessors
correspondent tous deux à la classe Android dans l'annotation @InstallIn
sur l'interface @EntryPoint
:
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(); } }
Dans cet exemple, vous devez utiliser l'ApplicationContext
pour récupérer le point d'entrée, car il est installé dans SingletonComponent
. Si la liaison que vous souhaitez récupérer se trouve dans ActivityComponent
, utilisez plutôt l'ActivityContext
.
Hilt et Dagger
Hilt repose sur la bibliothèque d'injection de dépendances Dagger et permet d'intégrer Dagger à une application Android de manière standard.
En ce qui concerne Dagger, les objectifs de Hilt sont les suivants :
- Simplifier l'infrastructure liée à Dagger pour les applications Android.
- Créer un ensemble standard de composants et de champs d'application pour faciliter la configuration, la lisibilité et le partage de code entre les applications.
- Offrir un moyen simple de fournir différentes liaisons pour divers types de compilation, tels que des tests, des débogages ou des versions.
Étant donné que le système d'exploitation Android instancie un grand nombre de ses propres classes de framework, l'utilisation de Dagger dans une application Android nécessite une quantité importante de code récurrent. Hilt réduit le code récurrent nécessaire à l'utilisation de Dagger dans une application Android. Hilt génère et fournit automatiquement les éléments suivants :
- Des composants permettant d'intégrer des classes du framework Android avec Dagger, qu'il faudrait sinon créer manuellement.
- Des annotations de champ d'application à utiliser avec les composants générés automatiquement par Hilt.
- Des liaisons prédéfinies pour représenter des classes Android telles que
Application
ouActivity
. - Des qualificatifs prédéfinis pour représenter
@ApplicationContext
et@ActivityContext
.
Le code de Dagger et celui de Hilt peuvent coexister dans le même codebase. Toutefois, dans la plupart des cas, il est préférable d'utiliser Hilt pour gérer l'ensemble de votre utilisation de Dagger sur Android. Pour migrer un projet qui utilise Dagger vers Hilt, consultez le guide de migration et l'atelier de programmation sur la migration de Dagger vers Hilt.
Ressources supplémentaires
Pour en savoir plus sur Hilt, consultez les ressources supplémentaires suivantes.
Exemples
Ateliers de programmation
Blogs
- Injection de dépendances sur Android avec Hilt
- Définition du champ d'application dans Android et Hilt
- Ajouter des composants à la hiérarchie de Hilt
- Migrer l'application Google I/O vers Hilt