Una forma fácil de usar Dependency Injection en su aplicación de Android
Hilt es una nueva biblioteca de inyección de dependencias construida sobre Dagger que facilita su uso en aplicaciones de Android. Esta guía muestra las características principales con algunos fragmentos de código para ayudarlo a comenzar a usar Hilt en su proyecto.
Para configurar Hilt en su aplicación, primero siga la guía de configuración de Gradle Build.
Una vez que haya instalado todas las dependencias y complementos, escriba su archivo Application
clase con @HiltAndroidApp
utilizar empuñadura. No es necesario hacer nada más ni invocarlo directamente.
Cuando escribe código que usa la inyección de dependencia, hay dos componentes principales en los que pensar:
- Clases que tienen dependencias que desea inyectar.
- Clases que se pueden inyectar como dependencias.
Estos no son mutuamente excluyentes y, en muchos casos, su clase es inyectable y tiene adicciones.
Hacer una adicción inyectable
Para crear algo inyectable en Hilt, debe decirle a Hilt cómo crear una instancia de esa cosa. Estas instrucciones se llaman ataques.
Hay tres formas de definir un enlace en Elsa.
- Tenga en cuenta el constructor con
@Inject
- Utilizar
@Binds
en una forma - Utilizar
@Provides
en una forma
⮕ Tenga en cuenta el constructor con @Inject
Cualquier clase puede tener un constructor anotado con @Inject
lo que lo hace disponible como dependencia en cualquier parte del proyecto.
⮕ Usando un formulario
Las otras dos formas de crear algo inyectable en Hilt implican el uso de formularios.
Un módulo de Hilt se puede considerar como una colección de «recetas» que le dicen a Hilt cómo crear una instancia de algo que no tiene un constructor, como una interfaz o un servicio del sistema.
Además, cualquier módulo se puede reemplazar en las pruebas con un módulo diferente. Esto hace que sea más fácil, por ejemplo, reemplazar implementaciones de interfaz con simulacros.
Los módulos se instalan en un componente de Hilt especificado utilizando el @InstallIn
anotación. Explicaré esto con más detalle más adelante.
Opción 1: usar @Binds
para crear la asociación para una interfaz
Si quieres usar OatMilk
en código cuando Milk
es necesario, cree un método abstracto dentro de un módulo y anótelo con @Binds
. Tenga en cuenta que OatMilk
debe ser inyectable en sí mismo para que esto funcione, lo que puede lograr notando su constructor con @Inject
.
Opción 2: usar @Provides
para crear una función de fábrica
Cuando no se puede crear una instancia directamente, puede crear un proveedor. Un proveedor es una función de fábrica que devuelve una instancia de un objeto.
Un ejemplo de esto es un servicio de sistema como ConnectivityManager
que debe obtenerse de un contexto.
los Context
el artículo es inyectable de forma predeterminada, siempre que lo anote con uno @ApplicationContext
o @ActivityContext
.
Inyectar una adicción
Una vez que sus adicciones sean inyectables, puede inyectarlas usando Hilt de dos maneras.
- Como parámetros de constructor
- Como campos
⮕ Como parámetros de constructor
Si el fabricante está marcado con @Inject
, Hilt inserta todos los parámetros basados en los enlaces definidos para esos tipos.
⮕ Campos similares
Si la clase es un punto de entrada, especifique aquí usando el @AndroidEntryPoint
anotación (más sobre esto en la siguiente sección), todos los campos anotados con @Inject
se inyectan.
Campos anotados con @Inject
debe ser público. También conviene prepararlos lateinit
para evitar hacerlos anulables, ya que su valor inicial antes de la inyección es null
.
Tenga en cuenta que insertar dependencias como campos solo es útil cuando su clase necesita tener un constructor sin parámetros, como Activity
. En la mayoría de los casos, recomendamos que inyecte a través de los parámetros del constructor.
Punto de entrada
Recuerda cuando dije que en muchos casos tu clase se crea por inyección es ¿Tiene dependencias inyectadas en él? En algunos casos tendrás una clase que no es creado a través de la inyección de dependencias, pero todavía tiene dependencias inyectadas en él. Un buen ejemplo de esto son las actividades, que normalmente son creadas por el marco de Android en lugar de Hilt.
Estas clases son Puntos de entrada en el cuadro de dependencias de Hilt y Hilt, necesita saber que tienen dependencias que deben inyectarse.
⮕ Punto de entrada de Android
La mayoría de sus puntos de entrada serán uno de los denominados puntos de entrada de Android:
- Ocupaciones
- Fragmento
- Ver
- Servicio
- Receptor de radiodifusión
Si es así, escríbalo con @AndroidEntryPoint
.
⮕ Otros puntos de entrada
La mayoría de las aplicaciones solo necesitan puntos de entrada de Android, pero si está interactuando con bibliotecas que no son de Dagger o componentes de Android que aún no son compatibles con Hilt, es posible que deba crear su propio punto de entrada para acceder manualmente al gráfico de Hilt. Puede leer más sobre cómo convertir clases arbitrarias en puntos de entrada.
ViewModel
UNA ViewModel
es un caso especial: no se crea una instancia directamente, ya que el marco tiene que crearlos, pero tampoco es un punto de entrada de Android. En lugar, ViewModel
s usa el especial @ViewModelInject
anotación que permite a Hilt inyectarles dependencias cuando se crean usando by viewModels()
, similar a me gusta @Inject
funciona para otras clases.
Para que esto funcione, deberá agregar algunas dependencias más. Para obtener más información, consulte las integraciones de Hilt y Jetpack.
Componentes
Cada módulo se instala dentro de un componente Hilt, especificado mediante @InstallIn(<component>)
. El componente del módulo se utiliza principalmente para evitar la inserción accidental de una dependencia en el lugar incorrecto. Por ejemplo, @InstallIn(ServiceComponent.class)
evitaría que el enlace y el proveedor del módulo anotado se utilicen en una actividad.
Además, puede definir un enlace para el componente en el que se encuentra el módulo. Lo que me lleva a …
Areas
De forma predeterminada, las asociaciones no tienen ámbito. En el ejemplo anterior, esto significa que cada vez que se inyecta Milk
, obtén una nueva instancia de OatMilk
. Si agrega el @ActivityScoped
anotación, el alcance de la asociación un ActivityComponent
.
Ahora que su formulario tiene alcance, Hilt solo creará uno OatMilk
por instancia de negocio. Aparte de eso OatMilk
La instancia estará ligada al ciclo de vida de esa actividad; se creará cuando la actividad onCreate()
se llama y se destruye cuando la actividad es onDestroy()
se llama.
En este caso, ambos milk
es moreMilk
apuntará a lo mismo OatMilk
ejemplo. Sin embargo, si tiene varias instancias de LatteActivity
, cada uno tendrá su propia instancia de OatMilk
.
En consecuencia, otras dependencias inyectadas en esta actividad tienen el mismo alcance y, por lo tanto, también usarán la misma instancia de OatMilk
:
El alcance depende del componente en el que esté instalado el módulo, p. Ej. @ActivityScoped
solo se puede aplicar a asociaciones dentro de un módulo instalado dentro ActivityComponent
.
El alcance también determina el ciclo de vida de las instancias inyectadas: en este caso, la instancia única de Milk
usado por Fridge
es LatteActivity
se crea cuando onCreate()
es requerido LatteActivity
– y destruido en su onDestroy()
. Esto también significa nuestro Milk
no «sobreviviría» a un cambio de configuración, ya que esto implicaría una llamada a onDestroy()
sobre la actividad. Puede solucionar esto mediante el uso de un alcance con un ciclo de vida más largo, por ejemplo @ActivityRetainedScope
.
Para obtener una lista de los ámbitos disponibles, los componentes a los que corresponden y los ciclos de vida correspondientes que siguen, consulte Componentes de Hilt.
Inyección del proveedor
A veces, desea un control más directo sobre la creación de instancias inyectadas. Por ejemplo, es posible que desee inyectar una o más instancias de algo solo cuando sea necesario, según su lógica empresarial. En este caso, puede utilizar dagger.Provider
.
La inyección de proveedor se puede utilizar independientemente de cuál sea la dependencia y cómo se inyecte. Todo lo que se pueda inyectar se puede envolver dentro Provider<…>
para que use la inyección del proveedor en su lugar.