Imagen de cabecera

De RoboGuice a Dagger 2

Cómo migrar de un a librería a la otra teniendo en cuenta la independencia de las librerías, la sobrecarga de módulos y las dependencias cíclicas.

Esta es la introducción del tutorial de migración de RoboGuice a Dagger 2. Aquí tienes el enlace a cada una de las partes que lo componen:

Introducción

Trabajando para mi empresa, recibí un proyecto externo que utilizaba la librería RoboGuice para la inyección de dependencias. El proyecto consiste en una aplicación con una librerías. Las inyección de dependencias estaba configuradas dentro de ambas con RoboGuice. Mi misión: eliminar RoboGuice, que ha quedado obsoleta desde hace ya dos años, y migrar a Dagger 2.

Las grandes diferencias entre RoboGuice y Dagger

En Dagger 1 teníamos el ObjectGraph, que en Dagger 2 se convierte en la clase Component, con el fin de poder dividir el ObjectGraph en varios componentes y hacer uso de los ámbitos (scopes). Para inyectar algo necesitamos tener acceso a una instancia de esta clase Component en cualquier lugar en el que queramos inicializar la inyección.

En RoboGuice, por el contrario, estamos abstraídos del grafo de dependencias. Uno solo tiene que hacer que sus clases con ciclo de vida hereden de unas clases homónimas de RoboGuice (Activity -> RoboActivity, Fragment -> RoboFragment…) y utilizar un inyector (Injector) en las clases que no tienen ciclo de vida, y él solo se encarga de inicializar la inyección.

De esta diferencia en el funcionamiento surgen los siguientes problemas:

Pérdida de la independencia de las librerías

Mientras que en RoboGuice la inyección funciona de manera automática en las clases con ciclo de vida y obteniendo una instancia de la clase Injector en el resto, en Dagger ambos tipos de clases necesitan un “injector” como el de RoboGuice y este no pertenece a la librería de Dagger, sino que hay que crearlo a mano y hacer que esté disponible en cualquier lugar en el que tengamos que inicializar las dependencias, lo que hace necesario que, o bien tanto la librería como aplicación tengan el mismo componente, o bien cada una gestione el suyo propio.

El primer caso es una vergüenza en términos de desacoplamiento, ya que la librería se vería obligada a conocer el componente de la aplicación que la va a utilizar y nunca podría ser independiente ni reutilizables. En el segundo, el problema vendría con el patrón singleton. Dos componentes distintos (o incluso dos instancias de un mismo componente) crean dos instancias que son únicas pero distintas entre sí. Por lo que no podemos tener independencia de librería e instancias realmente únicas en el .apk final.

Sobrecarga de módulos

Parece ser que en RoboGuice podemos sobrescribir todos los providers de un módulo con los providers que se declaren en otro. Mira la orden con la que se inicializa RoboGuice:

RoboGuice recibe los módulos en los que se especifica cómo proveer instancias de cada clase y ya está listo para inyectarlas. Pero ¿y esta línea tan extraña?

Esta línea devuelve un módulo que resulta de combinar el de la librería y el de la aplicación en uno solo, resolviendo que, cuando ambos módulos tengan un método proveedor repetido (es decir, que devuelvan la misma instancia), prevalezca el de la aplicación. En otras palabras, lo sobrescribe.

Es decir, que si la librería permite inyectar un String con el valor “lib” y la aplicación permite inyectar un String con el valor “app”, RoboGuice hace que siempre se inyecte el valor “app”, tanto en las clases que gestione la librería internamente como en las de la aplicación. Dagger, por el contrario, con un solo componente, sí que devolvería el valor “app” para la librería y la aplicación pero nos cargaríamos la independencia de la librería. Y sin embargo con dos componentes devolvería “app” para la aplicación y “lib” para la librería, por lo que nos cargamos el patrón singleton.

Dependencias cíclicas

RoboGuice permite que una clase A tenga inyectada una clase B y que B también tenga inyectada a A. Esto en Dagger no se puede hacer, ya que, en la inicialización de A se inicializaría B, la cual necesitaría inicializar A, que volvería a requerir la inicialización de B, y así hasta que obtuviéramos un error por falta de memoria.

Aclaraciones previas

Vamos a aclarar algunos términos de Dagger para que entendamos qué hacen:

El módulo

Es un conjunto de métodos provider. Sirve para indicar qué objetos se pueden inyectar.
La propiedad includes sirve para que el módulo se agencie todos los métodos de los módulos que incluya.

El componente

  • modules: para resolver dependencias, el componente utiliza los providers de los módulos indicados.
  • dependencies: para resolver dependencias, el componente utiliza los providers expuestos en los componentes indicados. Solo los expuestos. Pero para hacer esto, el módulo que añadas como dependencia no puede tener ámbito.

En base a todos los providers de los módulos que contenga y a las clases que hayamos hecho inyectables marcando su constructor con @Inject, se crea un componente, en el cual no puede haber providers duplicados. Si tenemos cinco módulos añadidos a un componente, entre los cinco no puede haber más de un provider para un mismo tipo objeto.

Cuando llamas a getComponent.inject(), lo que haces es inicializar todos los campos marcados con @Inject de la clase en la que lo llamas. En el componente tiene que haber necesariamente un provider (en sus módulos o expuesto en alguno de los componentes de los que depende) para satisfacer cada campo inyectado.

¡Empecemos pues!

Bien, aclarados estos conceptos, vamos a divir la migración en tres pasos:

  1. Conversión de RoboGuice a Dagger
  2. Sobrescritura de módulos
  3. Dependencias cíclicas

La primera parte es imprescindible; la segunda y la tercera pueden darse en el proceso de conversión según tu proyecto. Lee la introducción de cada una para saber si es algo que necesitas hacer o no.

0 Comentarios

Contesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

*

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

©2018 Codictados Comunidad libre para el aprendizaje de codigo Online

o

Inicia Sesión con tu Usuario y Contraseña

o    

¿Olvidó sus datos?

o

Create Account