En este tutorial verás una introducción para inyectar dependencias con Hilt en Android. Cada paso se ilustrará con un ejemplo simple que podrás descargar al final.
La Librería Hilt
Hilt es una librería de inyección de dependencias que hace parte del Android Jetpack.
Su objetivo es ayudarte a reducir el código repetitivo a la hora de implementar inyección de dependencias manual en tus proyectos Android.
A continuación verás los pasos para inyectar dependencias con Hilt.
1. Añadir Dependencias De Hilt
Usar Hilt en tu app Android requiere enlazar el siguiente plugin en tu archivo build.gradle
a nivel de proyecto:
buildscript {
/*...*/
ext.hilt_version = "2.28-alpha"
dependencies {
/*...*/
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
/*...*/
}
}
Luego aplica los siguientes plugins y dependencias de gradle en tu archivo de módulo:
plugins {
/*...*/
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'
}
android {
/*...*/
}
dependencies {
/*...*/
// Hilt
implementation "com.google.dagger:hilt-android:$hilt_version"
kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
/*...*/
}
Completa la configuración, usando el JDK 8 de Java en app/build.gradle
, debido a que Hilt usa características de allí:
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
2. Crear Clase Application Para Hilt
Hilt demanda que añadas una clase que herede de Application
.
Recuerda que Application
es el lugar en común, al que la mayoría de los componentes de Android pueden acceder. Esto hace que su clase derivada sea un excelente contenedor de dependencias. Ligando su esperanza de vida al de la app Android.
Al crear la subclase, anótala con @HiltAndroidApp
para marcarla como el componente contenedor de dependencias.
@HiltAndroidApp
class CardsApplication : Application() {
/*...*/
}
No olvides hacer referencia desde el AndroidManifest
en el atributo android:name
de la etiqueta <application>
.
<application
android:name=".CardsApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.IntroducciónAHilt">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
3. Inyectar Dependencias Con Hilt
Para hacer que tus subclases del framework de Android hagan uso de Hilt, márcalas con @AndroidEntryPoint
. Esto creará un contenedor de dependencias que es consciente del ciclo de vida de la clase.
Luego materializa el consumo de la dependencia en un campo, usando la anotación @Inject
.
Por ejemplo: En nuestro ejemplo de cartas deseamos inyectar la fuente local directamente en el fragmento para cargas la lista de datos:
@AndroidEntryPoint
class CardsFragment : Fragment() {
@Inject
lateinit var cardsLocalStore: CardsLocalStore
/*...*/
}
La solución consiste en usar una propiedad miembro de inicio tardío (cardsLocalStore
) marcada con @Inject
.
Puntos De Entrada Dependientes
Si anotas una clase de la cual dependa otra, como los fragmentos con las actividades, entonces debes anotarla también.
Eso es lo que pasa con CardsActivity
en nuestro ejemplo, si no la anotas tendrás el siguiente error:
Hilt Fragments must be attached to an @AndroidEntryPoint Activity. Found: class com.develou.hilt1.cards.CardsActivity
Por lo que será indispensable que recuerdes anotar a tus actividades:
@AndroidEntryPoint
class CardsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_cards)
supportFragmentManager.commit {
replace(R.id.container, CardsFragment())
addToBackStack("Main")
}
}
}
4. Enlazar Constructores A La Inyección
Obviamente marcar el campo no es suficiente para que se genere el código necesario de inyección de la dependencia.
Por eso debes ir al constructor de la clase y anotarlo con @Inject
para decirle a Hilt como proveer la instancia del tipo que deseas inyectar.
En el caso de la fuente local, completaremos la relación anotándola así:
class CardsLocalStore @Inject constructor() {
fun getLocalCards() = listOf("Carta 1", "Carta 2", "Carta 3")
}
Esto hará que Android Studio muestre un ícono que informa la provisión/binding de la dependencia «CardsLocalStore() provides for CardsFragment».
Y que también marque el consumo desde el fragmento:
Si presionas ambos iconos podrás navegar entre el binding y el consumo.
Ejemplo Con Hilt
El ejemplo discutido resuelve un caso de uso de lista, que muestra la colección de cartas de un juego para el usuario. Por cuestiones de simplicidad la interfaz es esta:
Puedes descargar el ejemplo visto en este tutorial de inyección de dependencias con Hilt desde el siguiente link.
A lo largo de los siguientes tutoriales este ejemplo irá creciendo para mostrar otros casos de inyección.
¿Qué Sigue?
Ahora puedes ir a ver el uso de módulos en Hilt (por escribir), los cuáles te permitirá proveer dependencias de clases a las cuáles no tienes acceso de construcción o para la creación de ejemplares de interfaces.