Hilt es una biblioteca de inserción de dependencias para Android que permite reducir el trabajo repetitivo de insertar dependencias de forma manual en tu proyecto. Para la inserción manual de dependencias, debes construir cada clase y sus dependencias de forma manual, y usar contenedores para reutilizar y administrar las dependencias.
Hilt proporciona una forma estándar de usar la inserción de dependencias en tu aplicación, ya que proporciona contenedores para cada clase de Android en tu proyecto y administra automáticamente sus ciclos de vida. Hilt se basa en la popular biblioteca de inserción de dependencias Dagger y se beneficia de la corrección en tiempo de compilación, el rendimiento del entorno de ejecución, la escalabilidad y la compatibilidad con Android Studio que proporciona. Para obtener más información, consulta Hilt y Dagger.
En esta guía, se explican los conceptos básicos de Hilt y los contenedores que este genera. También se incluye una demostración de cómo realizar un arranque de una app existente para usar Hilt.
Cómo agregar dependencias
Primero, agrega el complemento hilt-android-gradle-plugin
al archivo build.gradle
raíz de tu proyecto:
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 }
Luego, aplica el complemento de Gradle y agrega estas dependencias a tu archivo 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 usa funciones de Java 8. Para habilitar Java 8 en tu proyecto, agrega lo siguiente al archivo 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 } }
Clase de aplicación de Hilt
Todas las apps que usan Hilt deben contener una clase Application
anotada con @HiltAndroidApp
.
@HiltAndroidApp
activa la generación de código de Hilt, incluida una clase base para tu aplicación que sirve como contenedor de dependencia a nivel de la aplicación.
Kotlin
@HiltAndroidApp class ExampleApplication : Application() { ... }
Java
@HiltAndroidApp public class ExampleApplication extends Application { ... }
Se adjunta este componente generado por Hilt al ciclo de vida del objeto Application
y le proporciona dependencias. Además, es el componente superior de la app, lo que significa que otros componentes pueden acceder a las dependencias que proporciona.
Cómo inyectar dependencias en clases de Android
Una vez que se configura Hilt en tu clase Application
y hay un componente disponible en el nivel de la aplicación, Hilt puede proporcionar dependencias para otras clases de Android que tengan la anotación @AndroidEntryPoint
:
Kotlin
@AndroidEntryPoint class ExampleActivity : AppCompatActivity() { ... }
Java
@AndroidEntryPoint public class ExampleActivity extends AppCompatActivity { ... }
En la actualidad, la versión de Hilt admite las siguientes clases de Android:
Application
(mediante@HiltAndroidApp
)ViewModel
(mediante@HiltViewModel
)Activity
Fragment
View
Service
BroadcastReceiver
Si anotas una clase de Android con @AndroidEntryPoint
, también debes anotar las clases de Android que dependen de ella. Por ejemplo, si anotas un fragmento, también debes anotar todas las actividades en las que uses ese fragmento.
@AndroidEntryPoint
genera un componente individual de Hilt para cada clase de Android de tu proyecto. Estos componentes pueden recibir dependencias de sus respectivas clases superiores, como se describe en Jerarquía de los componentes.
Para obtener dependencias de un componente, usa la anotación @Inject
a fin de realizar la inyección de campo:
Kotlin
@AndroidEntryPoint class ExampleActivity : AppCompatActivity() { @Inject lateinit var analytics: AnalyticsAdapter ... }
Java
@AndroidEntryPoint public class ExampleActivity extends AppCompatActivity { @Inject AnalyticsAdapter analytics; ... }
Las clases que se pueden insertar con Hilt pueden tener otras clases base que también usen la inserción.
Esas clases no necesitan la anotación @AndroidEntryPoint
si son abstractas.
Para obtener más información acerca de en qué devolución de llamada de ciclo de vida se inserta una clase de Android, consulta Ciclos de vida de los componentes.
Cómo definir las vinculaciones de Hilt
Para realizar la inyección de campo, Hilt debe saber cómo proporcionar instancias de las dependencias necesarias del componente correspondiente. Una vinculación contiene la información necesaria para proporcionar instancias de un tipo como dependencia.
Una forma de proporcionar información de vinculación a Hilt es la inyección de constructor. Usa la anotación @Inject
en el constructor de una clase para indicarle a Hilt cómo proporcionar instancias de esa clase:
Kotlin
class AnalyticsAdapter @Inject constructor( private val service: AnalyticsService ) { ... }
Java
public class AnalyticsAdapter { private final AnalyticsService service; @Inject AnalyticsAdapter(AnalyticsService service) { this.service = service; } ... }
Los parámetros de un constructor anotado de una clase son las dependencias de esa clase. En el ejemplo, AnalyticsAdapter
tiene AnalyticsService
como dependencia. Por lo tanto, también debe proporcionar instancias de AnalyticsService
.
Módulos de Hilt
A veces, el tipo no se puede insertar con un constructor, lo que puede suceder por varios motivos. Por ejemplo, no puedes insertar una interfaz con un constructor. Tampoco puedes inyectar con un constructor un tipo que no sea de tu propiedad, como una clase de una biblioteca externa. En estos casos, puedes proporcionar información de vinculación mediante módulos de Hilt.
Un módulo de Hilt es una clase anotada con @Module
. Al igual que los módulos de Dagger, informa a Hilt cómo proporcionar instancias de determinados tipos. A diferencia de los módulos de Dagger, debes anotar los módulos de Hilt con @InstallIn
para indicarle a Hilt en qué clase de Android se usará o instalará cada módulo.
Las dependencias que proporcionas en los módulos de Hilt están disponibles en todos los componentes generados que están asociados con la clase de Android en la que instalas el módulo de Hilt.
Cómo inyectar instancias de interfaces con @Binds
Considera el ejemplo de AnalyticsService
. Si AnalyticsService
es una interfaz, no puedes inyectarla con un constructor. En cambio, debes proporcionarle a Hilt la información de vinculación creando una función abstracta anotada con @Binds
dentro de un módulo de Hilt.
La anotación @Binds
le indica a Hilt qué implementación debe usar cuando necesite proporcionar una instancia de una interfaz.
La función anotada le proporciona a Hilt la siguiente información:
- El tipo de datos que muestra la función le indica a Hilt las instancias de qué interfaz proporciona la función.
- El parámetro de la función le indica a Hilt qué implementación debe proporcionar.
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 ); }
El módulo AnalyticsModule
de Hilt está anotado con @InstallIn(ActivityComponent.class)
porque deseas que Hilt inyecte esa dependencia en ExampleActivity
. Esta anotación indica que todas las dependencias de AnalyticsModule
están disponibles en todas las actividades de la app.
Cómo insertar instancias con @Provides
Las interfaces no son el único caso en el que no puedes insertar un tipo con un constructor.
La inserción de constructor tampoco es posible si la clase no es de tu propiedad porque proviene de una biblioteca externa (clases como Retrofit, OkHttpClient
o bases de datos de Room), o si las instancias deben crearse con el patrón de compilador.
Considera el ejemplo anterior. Si la clase AnalyticsService
no es de tu propiedad, puedes indicarle a Hilt cómo proporcionar instancias de este tipo creando una función dentro de un módulo de Hilt y anotando esa función con @Provides
.
La función anotada le proporciona a Hilt la siguiente información:
- El tipo de datos que se muestra le indica a Hilt las instancias de qué tipo proporciona la función.
- Los parámetros de la función le indican a Hilt cuáles son las dependencias del tipo correspondiente.
- El cuerpo de la función le indica a Hilt cómo proporcionar una instancia del tipo correspondiente. Hilt ejecuta el cuerpo de la función cada vez que necesita proporcionar una instancia de ese tipo.
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); } }
Cómo proporcionar varias vinculaciones para el mismo tipo
En los casos en los que necesites que Hilt proporcione diferentes implementaciones del mismo tipo como dependencias, debes proporcionarle varias vinculaciones. Puedes definir varias vinculaciones para el mismo tipo con calificadores.
Un calificador es una anotación que se usa para identificar una vinculación específica de un tipo cuando ese tipo tiene varias vinculaciones definidas.
Considera el ejemplo. Si necesitas interceptar llamadas a AnalyticsService
, puedes usar un objeto OkHttpClient
con un interceptor. En otros servicios, es posible que debas interceptar llamadas de otra manera. En ese caso, debes indicarle a Hilt cómo proporcionar dos implementaciones diferentes de OkHttpClient
.
Primero, define los calificadores que usarás para anotar los métodos @Binds
o @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 {}
Luego, Hilt necesita saber cómo proporcionar una instancia del tipo correspondiente a cada calificador. En este caso, puedes usar un módulo de Hilt con @Provides
.
Ambos métodos muestran el mismo tipo de datos, pero los calificadores los etiquetan como dos vinculaciones diferentes:
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(); } }
Puedes inyectar el tipo específico que necesitas anotando el campo o parámetro con el calificador correspondiente:
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; ... }
Según la práctica recomendada, si agregas un calificador a un tipo, debes agregar calificadores a todas las formas posibles en que se proporciona esa dependencia. Si sales de la implementación base o común sin un calificador, se pueden producir errores y Hilt podría insertar una dependencia incorrecta.
Calificadores predefinidos en Hilt
Hilt proporciona algunos calificadores predefinidos. Por ejemplo, debido a que podrías necesitar la clase Context
de la aplicación o de la actividad, Hilt proporciona los calificadores @ApplicationContext
y @ActivityContext
.
Supongamos que la clase AnalyticsAdapter
del ejemplo necesita el contexto de la actividad. En el siguiente código, se muestra cómo proporcionar el contexto de la actividad a 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; } }
Para obtener información sobre otras vinculaciones predefinidas disponibles en Hilt, consulta Vinculaciones predeterminadas de los componentes.
Componentes generados para clases de Android
Para cada clase de Android en la que puedes realizar la inserción de campo, hay un componente de Hilt asociado al que puedes hacer referencia en la anotación @InstallIn
.
Cada componente de Hilt es responsable de inyectar sus vinculaciones en la clase de Android correspondiente.
En los ejemplos anteriores, se demostró el uso de ActivityComponent
en los módulos de Hilt.
Hilt proporciona los siguientes componentes:
Componente de Hilt | Inyector para |
---|---|
SingletonComponent |
Application |
ActivityRetainedComponent |
N/A |
ViewModelComponent |
ViewModel |
ActivityComponent |
Activity |
FragmentComponent |
Fragment |
ViewComponent |
View |
ViewWithFragmentComponent |
View anotada con @WithFragmentBindings |
ServiceComponent |
Service |
Ciclos de vida de los componentes
Hilt crea y destruye automáticamente instancias de clases generadas por componentes siguiendo el ciclo de vida de las clases de Android correspondientes.
Componente generado | Creado en | Destruido en |
---|---|---|
SingletonComponent |
Application#onCreate() |
Se destruyó Application |
ActivityRetainedComponent |
Activity#onCreate() |
Activity#onDestroy() |
ViewModelComponent |
Se creó ViewModel |
Se destruyó ViewModel |
ActivityComponent |
Activity#onCreate() |
Activity#onDestroy() |
FragmentComponent |
Fragment#onAttach() |
Fragment#onDestroy() |
ViewComponent |
View#super() |
Se destruyó View |
ViewWithFragmentComponent |
View#super() |
Se destruyó View |
ServiceComponent |
Service#onCreate() |
Service#onDestroy() |
Alcances de los componentes
De forma predeterminada, en Hilt, las vinculaciones no tienen alcance. Esto significa que, cada vez que tu app solicita la vinculación, Hilt crea una instancia nueva del tipo necesario.
En el ejemplo, cada vez que Hilt proporciona AnalyticsAdapter
como dependencia a otro tipo o mediante la inserción de campo (como en ExampleActivity
), también proporciona una nueva instancia de AnalyticsAdapter
.
Sin embargo, también permite que una vinculación tenga un alcance para un componente en particular. Hilt solo crea una vinculación con alcance una vez por instancia del componente al que se aplica la vinculación y todas las solicitudes para esa vinculación comparten la misma instancia.
En la siguiente tabla, se enumeran las anotaciones de alcance para cada componente generado:
Clase de Android | Componente generado | Alcance |
---|---|---|
Application |
SingletonComponent |
@Singleton |
Activity |
ActivityRetainedComponent |
@ActivityRetainedScoped |
ViewModel |
ViewModelComponent |
@ViewModelScoped |
Activity |
ActivityComponent |
@ActivityScoped |
Fragment |
FragmentComponent |
@FragmentScoped |
View |
ViewComponent |
@ViewScoped |
View anotada con @WithFragmentBindings |
ViewWithFragmentComponent |
@ViewScoped |
Service |
ServiceComponent |
@ServiceScoped |
En el ejemplo, si defines el alcance de AnalyticsAdapter
mediante ActivityComponent
con @ActivityScoped
, Hilt proporciona la misma instancia de AnalyticsAdapter
durante el ciclo de vida de la actividad correspondiente:
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; } ... }
Supongamos que AnalyticsService
tiene un estado interno que requiere que se use siempre la misma instancia (no solo en ExampleActivity
, sino en cualquier parte de la app). En este caso, es apropiado establecer el alcance de AnalyticsService
en el SingletonComponent
. Como resultado, cada vez que el componente necesita proporcionar una instancia de AnalyticsService
, proporciona siempre la misma instancia.
En el siguiente ejemplo, se muestra cómo definir el alcance de una vinculación a un componente en un módulo de Hilt. El alcance de una vinculación debe coincidir con el alcance del componente en el que está instalada, de modo que en este ejemplo debes instalar AnalyticsService
en SingletonComponent
, en lugar de 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); } }
Para obtener más información sobre los alcances de los componentes de Hilt, consulta Alcance en Android y Hilt.
Jerarquía de los componentes
Instalar un módulo en un componente permite acceder a sus vinculaciones como una dependencia de otras vinculaciones, en ese componente o en cualquier componente secundario de la jerarquía de componentes:
Vinculaciones predeterminadas de los componentes
Cada componente de Hilt incluye un conjunto de vinculaciones predeterminadas que puede insertar como dependencias en tus propias vinculaciones personalizadas. Ten en cuenta que estas vinculaciones corresponden a la actividad y a los tipos de fragmentos generales, no a una subclase específica. Esto se debe a que Hilt usa una sola definición de componente de actividad para inyectar todas las actividades. Cada actividad tiene una instancia diferente de este componente.
Componente de Android | Vinculaciones predeterminadas |
---|---|
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 vinculación de contexto de la aplicación también está disponible si se usa @ApplicationContext
.
Por ejemplo:
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 vinculación de contexto de actividad también está disponible si se usa @ActivityContext
. Por ejemplo:
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; } }
Cómo inyectar dependencias en clases no compatibles con Hilt
Hilt incluye compatibilidad con las clases de Android más comunes. Sin embargo, es posible que debas realizar una inyección de campo en las clases que Hilt no admite.
En esos casos, puedes crear un punto de entrada mediante la anotación @EntryPoint
. Un punto de entrada es el límite entre el código que está administrado por Hilt y el código que no lo está. Es el punto en el que el código ingresa por primera vez en el grafo de objetos que Hilt administra. Los puntos de entrada le permiten a Hilt usar código que no administra a fin de proporcionar dependencias dentro del grafo de dependencias.
Por ejemplo, Hilt no admite directamente a los proveedores de contenido. Si quieres que un proveedor de contenido use Hilt para obtener algunas dependencias, debes definir una interfaz anotada con @EntryPoint
para cada tipo de vinculación que deseas e incluir calificadores. Luego, agrega @InstallIn
para especificar el componente en el que instalarás el punto de entrada, de la siguiente manera:
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(); } ... }
Para acceder a un punto de entrada, usa el método estático apropiado de EntryPointAccessors
. El parámetro debería ser la instancia del componente o el objeto @AndroidEntryPoint
que funciona como contenedor del componente. Asegúrate de que el componente que pasas como parámetro y el método estático EntryPointAccessors
coincidan con la clase de Android en la anotación @InstallIn
de la interfaz @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(); } }
En este ejemplo, debes usar el ApplicationContext
para recuperar el punto de entrada porque este está instalado en SingletonComponent
. Si la vinculación que quieres recuperar está en el ActivityComponent
, deberías usar el ActivityContext
.
Hilt y Dagger
Hilt se basa en la biblioteca de inserción de dependencias de Dagger, lo que proporciona una forma estándar de incorporar Dagger en una aplicación para Android.
Con respecto a Dagger, los objetivos de Hilt son los siguientes:
- Simplificar la infraestructura relacionada con Dagger para las apps de Android
- Crear un conjunto estándar de componentes y alcances para facilitar la configuración, la legibilidad y el uso compartido de código entre apps.
- Proporcionar una manera fácil de aprovisionar diferentes vinculaciones para varios tipos de compilación, como pruebas, depuración o lanzamiento
Debido a que el sistema operativo Android crea una instancia de muchas de sus propias clases de frameworks, si usas Dagger en una app para Android, deberás escribir una cantidad considerable de código estándar. Hilt permite reducir la cantidad de código estándar que implica el uso de Dagger en una aplicación para Android. Hilt genera y proporciona automáticamente lo siguiente:
- Componentes para integrar clases de frameworks de Android con Dagger que, de lo contrario, deberías crear a mano.
- Anotaciones de alcance para usar con los componentes que Hilt genera automáticamente.
- Vinculaciones predefinidas para representar clases de Android, como
Application
oActivity
. - Calificadores predefinidos para representar a
@ApplicationContext
y@ActivityContext
.
El código de Hilt y el de Dagger pueden coexistir en la misma base de código. Sin embargo, en la mayoría de los casos, lo mejor es usar Hilt para administrar todo el uso de Dagger en Android. Si deseas migrar un proyecto que usa Dagger a Hilt, consulta la guía de migración y el codelab Cómo migrar tu app de Dagger a Hilt.
Recursos adicionales
Para obtener más información sobre Hilt, consulta los siguientes recursos adicionales.
Ejemplos
Codelabs
Blogs
- Inserción de dependencias en Android con Hilt
- Alcance en Android y Hilt
- Cómo agregar componentes a la jerarquía de Hilt
- Cómo migrar la app de Google I/O a Hilt