Kotlin: Esto ya empieza a ponerse interesante... Dagger2 #AndroidMeetsKotlin
Francisco Manuel López Jurado Colaboraciones 24/11/2017
Siguiendo la línea de construcción de nuestra aplicación en Kotlin, hoy vamos a dar un paso significativo ya que usaremos nuestro primer contenedor de dependencias. En concreto vamos a detallar el uso de Dagger2 pero antes de comenzar a ver cómo implementarlo debemos tener muy claro por qué se usa y cuáles son sus conceptos más básicos.
Dagger2
Se trata de una biblioteca muy conocida e implantada en el desarrollo de apps en Android, en este caso vamos a usar su versión 2 ya que es la que más se usa en la actualidad.
Pero... “¿Có..., có..., cómo lo hace?”
Como todos los contenedores de dependencias, la creación del grafo de las mismas es sumamente importante, pero lo más interesante en Dagger2 es que esta creación se ha adelantado al tiempo de compilación pudiendo así descubrir los errores mucho antes que si fuese en tiempo de ejecución donde vamos a ciegas y luego nos encontramos con los errores (generalmente crashes de la app). Esta ventaja aporta más velocidad a la app ya que no necesita generar el grafo cada vez que se arranca la aplicación pudiendo así disminuir los tiempos de arranque.
Anotaciones
- @Module. Se usa para apuntar clases que proporcionan dependencias. Se notificará a Dagger en qué lugar se construyen los objetos requeridos.
- @Provides. Se usa para marcar los métodos en el módulo que devuelve dependencias.
- @Component. Esta anotación se utiliza para crear una interfaz que lo conecta todo junto, es una interfaz de puente entre los módulos y la inyección.
- @Inject. Solicita una dependencia (un constructor, un campo o un método).
Tienes más peligro que inyectar algo en Android...
Como todo no puede ser un camino de rosas, existen una serie de limitaciones a las que nos tenemos que adaptar queramos o no:
- Tendremos que convivir con los métodos onCreate y onResume de las Activities, ya que serán nuestros puntos de entrada a nuestras posibles inyecciones.
- La memoria de los dispositivos no es infinita por lo que cuidado con tener grafos gigantescos en nuestras aplicaciones ya que penalizará el rendimiento y con ello la velocidad de las mismas.
- Por todos es conocido que cuando Android decide matar tu app por sí mismo, todos los datos que tenga en memoria volátil se perderán, por lo que luego cuando queramos volver a abrirla se quedará en un estado erróneo. Debemos tener cuidado con esto y hacer que nuestro inyector de dependencias pueda restaurarse correctamente tal y como se quedó antes de que el usuario pasase tu app a segundo plano.
Una vez que ya conocemos los conceptos más básicos y los posibles errores que nos podemos encontrar y no añadir más complejidad de la cuenta, de momento sólo crearemos un módulo, un componente, una configuración del grafo inicial y una primera inyección. Sin más, vamos a dejar la teoría de un lado y empezamos a picar código, que para eso estamos aquí:
Dependencias que necesitamos
Necesitaríamos añadir las dependencias de Dagger en su versión 2.5.
Definición de la variable donde estará la versión de Dagger.
Además, es muy importante añadir el plugin de kapt que ayudará a Dagger en la creación de las clases necesarias para una correcta inyección.
Creamos el módulo
Crearemos nuestro primer módulo llamado AppModule.
Como se puede ver, tiene un constructor que recibe un parámetro app de tipo BetaBeersApplication y un método que nos proporcionará dicha variable. En esta ocasión tiene dos anotaciones:
- @Provides.
- @Singleton. Nos proporcionará una única instancia de este módulo, sin tener la necesidad de crearlo manualmente como estamos acostumbrados.
Creamos el Componente
Ahora necesitamos crear la clase AppComponent que tendrá un método para inyectar nuestra clase Application en nuestro grafo inicial y un listado con el módulo que hemos creado anteriormente.
Generación del grafo inicial
Necesitamos configurar nuestro módulo y componente creados en los apartados anteriores. En nuestra clase BetaBeersApplication. Para ello:
- Crearemos un objeto companion para definir la variable appComponent donde usaremos el patrón builder de la clase autogenerada por Dagger2 DaggerAppComponent. Si esta clase nos aparece marcada en rojo mostrando su no existencia, necesitaremos hacer un Build para que se autogenere. Una vez hecho esto, tenemos que establecer el módulo que hemos creado y finalmente invocar al método “build”. Todo esto debe estar encapsulado por la función lazy ya que necesitamos que solo se ejecute el lambda la primera vez que se invoque y en posteriores invocaciones retorne el objeto ya creado.
- En el método OnCreate debemos acceder a la variable appComponent y hacer uso de su método inject. Después de esto, ya tenemos correctamente nuestro componente configurado.
- Es importante que no olvidemos establecer nuestra implementación de la clase Application en el manifest, si no, todo lo anterior no funcionará.
Inyección
Por último, nos crearemos una variable como lateinit ya que necesitamos que no sea null y sea inicializada posteriormente por nuestro inyector de dependencias. Si accedemos a esta variable antes de que se inicialice correctamente, lanzará una excepción de tipo UninitializedPropertyAccessException.
Conclusiones
En este ejemplo básico, simplemente hemos visto cómo crear un componente, un módulo e inyectarlo correctamente. Es importante tener los conceptos básicos totalmente claros ya que en post posteriores empezaremos a añadir más complicaciones para crear una arquitectura que siga los estándares de calidad y mantenimiento sostenible. Espero que os haya gustado.