Hola chicos, ¡bienvenidos a Coding in Flow! En este tutorial, aprenderemos paso a paso cómo usar Dagger 2 y por qué debemos usarlo. Dagger 2 es un marco de inyección de dependencia para Android y Java y está desarrollado por Google. Pero, por supuesto, también puedes usarlo con Kotlin. Este tutorial está dirigido a principiantes que nunca antes han trabajado con Dagger y que ni siquiera saben qué es la inyección de dependencia. En la parte 1, daré una introducción general al concepto de inyección de dependencia y luego comenzaremos a usar Dagger 2 en las próximas partes.
Bien, comencemos aclarando qué es una dependencia. Si eres un programador de Android, lo primero que te viene a la mente cuando escuchas la palabra "dependencia" son probablemente las dependencias de Gradle porque aquí es donde escuchamos la palabra "dependencias" todo el tiempo. Pero esto no es lo que queremos decir cuando hablamos de dependencia aquí. En programación, el término "dependencia" solo significa que una clase usa otra clase. Entonces, si un objeto de clase A tiene una referencia a un objeto de clase B, entonces la clase A depende de la clase B y la clase B depende de la clase A. Entonces, la clase A necesita la clase B para realizar su trabajo. Por ejemplo, digamos que tenemos una clase de Usuario y una clase de Dirección, y la clase de Usuario contiene un campo para una Dirección, entonces la Dirección es una dependencia del Usuario. O un cargador de imágenes como Picasso o Glide usa internamente un cliente HTTP para cargar la imagen desde la web.
Entonces el cliente HTTP es una dependencia del cargador de imágenes. Y un RecyclerView necesita un Adaptador RecyclerView para crear las filas individuales, por lo que el Adaptador es una dependencia de RecyclerView. Y realmente tenemos estas dependencias en todas partes en la Programación Orientada a Objetos porque se supone que cada clase solo tiene una pequeña cantidad de responsabilidades y depende de otras clases para hacer su trabajo. Y la inyección simplemente significa pasar estas dependencias desde el exterior.
La idea aquí es que las clases no deberían ser responsables de crear sus propias dependencias o buscarlas. En su lugar, estas dependencias deben instanciarse en otro lugar y luego pasarse a la clase que las necesita. Más adelante en esta serie, veremos ejemplos específicos de Android, pero para una mejor comprensión, comenzaremos con un ejemplo abstracto e imaginamos que somos un fabricante de automóviles. Así que aquí tenemos la clase Coche que tiene 2 campos para Motor y Ruedas. Entonces Engine y Wheels son dependencias de Car, y lo que ves aquí sería sin ninguna inyección de dependencia. Porque en este momento en el constructor de automóviles, instanciamos un nuevo motor y nuevas ruedas, como puede ver en el nuevo operador aquí. Esto significa que, en este momento, nuestra clase Car es responsable de crear sus propios objetos Engine y Wheels. Entonces, cada vez que construimos un objeto Car, creamos automáticamente una instancia de Engine y una instancia de Wheels.
E imaginemos cómo se vería esto en la vida real. Entonces, digamos que tenemos una línea de ensamblaje de automóviles donde los trabajadores están construyendo un automóvil. Y ahora es el momento de poner el motor en el coche. Lo que hacemos aquí en este momento es el equivalente a los trabajadores corriendo y comenzando a ensamblar un motor completamente nuevo desde cero. Como tomar estas piezas individuales, juntarlas, configurar todo correctamente, etc. Y cada vez que crean un auto nuevo tienen que pasar por todo este proceso. Pero, por supuesto, no es así como funciona. En cambio, el motor se construye en otro lugar en paralelo y luego pasa a la línea de ensamblaje del automóvil como un objeto completo. Y si se realizan cambios en la forma en que se construye o configura el motor, nuestros trabajadores de la línea de ensamblaje no tienen que preocuparse por eso, porque simplemente toman la pieza completa y la colocan en el automóvil.
Además, es posible que queramos usar diferentes motores para el mismo modelo de automóvil, por ejemplo, con menos o más caballos de fuerza. Y en lugar de crear nuestras propias ruedas todo el tiempo, es posible que deseemos usar ruedas de un fabricante externo. Y cuando probemos nuestro automóvil, es posible que no queramos usar las mismas llantas costosas de alta calidad que también usamos en la producción. En su lugar, es posible que deseemos usar llantas baratas que sean lo suficientemente buenas para funcionar y básicamente imitar el comportamiento de las llantas caras. Y al proporcionar estas piezas desde el exterior, no tenemos que hacer ningún cambio en el proceso de construcción del automóvil. No importa qué ruedas o motor pongamos allí, porque los trabajadores no tienen que preocuparse por eso.
Simplemente agregan las piezas que se les proporcionan. Y es realmente la misma idea detrás de la inyección de dependencia. Un objeto Car no debe ser responsable de crear sus propias partes , sino que debemos pasarlas desde el exterior. ¿Y cómo le pasamos algo a una clase desde el exterior? Usualmente sobre su constructor o sobre un método setter. Y así desvinculamos el proceso de construcción del coche del proceso de construcción de su motor y ruedas. Y los beneficios son realmente similares al ejemplo de la línea de montaje. Ahora podemos cambiar fácilmente el motor y las ruedas por otros diferentes y podemos configurarlos fuera de la clase Coche, mientras que antes los codificamos en esta clase, por lo que solo podíamos hacer cambios directamente aquí. Y ahora, si alguien cambia el constructor de la clase Engine o Wheels , no tenemos que actualizar estos cambios en nuestra clase Car. Y esto también significa que ahora otros desarrolladores pueden trabajar en estas clases en paralelo sin interferir con nuestro trabajo en la clase Car. Debido a que no nos importa cómo se construyen estos objetos, simplemente queremos que pasen cuando estemos listos.
Esto también significa que ahora tenemos clases más pequeñas con menos responsabilidad porque nuestro automóvil no es responsable de crear un motor o ruedas. Su único trabajo es conducir, porque es un coche. Otro beneficio es que ahora podemos realizar pruebas unitarias más rápidas y sencillas de nuestra clase de automóviles. Porque la idea detrás de las pruebas unitarias es que solo probamos un componente aislado y no todas sus dependencias, especialmente en ejemplos del mundo real donde nuestra clase podría depender de recursos externos costosos como una base de datos, un servicio web o la ubicación del dispositivo, y nosotros no quiero probar estos recursos externos al mismo tiempo que probamos nuestra clase. En cambio, generalmente queremos burlarnos de estos objetos. Así que básicamente queremos usar objetos falsos que solo simulen su comportamiento en lugar de usar los reales. Pero esto es imposible si nuestra clase siempre construye estas instancias. Y también, en algunas situaciones, es posible que queramos usar el mismo objeto para satisfacer las dependencias de varios objetos diferentes, por lo que queremos compartir un objeto entre varias clases. Por ejemplo, supongamos que cuando nuestro automóvil está completamente construido, alguien tiene que sacarlo de la fábrica.
Pero, por supuesto, esto no necesita ser un nuevo conductor cada vez que se termina un automóvil. En cambio, podemos usar el mismo conductor para varios autos diferentes. Como ejemplo del mundo real: es posible que desee utilizar el mismo cliente HTTP para diferentes funciones de red, como cargar imágenes o realizar llamadas a la API REST. Y nuevamente, esto no es posible si estas clases siempre construyen sus propias dependencias. Pero con la inyección de dependencia lo es. Entonces, la inyección de dependencia en sí misma es solo un patrón de diseño, no es una biblioteca. Y casi todas las aplicaciones lo usan de alguna manera, incluso si es solo una cadena que le pasa al constructor de una clase.
Esto ya es una forma de inyección de dependencia, donde la cadena es la dependencia. Cuando llama a setAdapter() en un RecyclerView, realiza una inyección de dependencia. O cuando pasa el contexto a un método o constructor, inyecta contexto como dependencia. Entonces, para hacer la inyección de dependencia no se necesita Dagger u otra biblioteca. Entonces, ¿cuál es el propósito de Dagger? ¿Por qué deberíamos usarlo? Para esto, simplemente vayamos y construyamos uno de nuestros autos. Hagamos esto en nuestra MainActivity. En el método onCreate(), quiero crear un automóvil como nuevo Car(). Pero ahora definimos que tenemos que pasar un motor y ruedas. Así que hagamos esto… Necesitamos un Motor motor = nuevo Motor() Y necesitamos Ruedas ruedas = nuevas Ruedas() Luego se las pasamos a nuestro auto. Y luego podemos llamar a car.drive() Así que ahora, como puede ver, tenemos que inicializar bastante. Mientras que antes, cuando nuestro automóvil creaba sus propias dependencias, no teníamos que hacer estas cosas porque no teníamos que pasarlas como argumentos. Y ahora digamos que nuestro Motor y Ruedas tienen sus propias dependencias. Por ejemplo, nuestro Motor podría consistir en un bloque de motor, cilindros y bujías.
Y las ruedas necesitan neumáticos y llantas. Y tenemos que instanciar todos estos objetos aquí y luego pasarlos a nuestro motor y ruedas. Y, por supuesto, esto podría continuar para muchos objetos diferentes y en diferentes lugares de nuestra aplicación. Entonces, esta inyección de dependencia manual realmente contamina todos nuestros sitios de llamadas. Y este es realmente el inconveniente aquí. Y ahora, cada vez que cambiamos un constructor o cómo tenemos que configurar una de estas clases , tenemos que actualizar estos cambios en todas partes, lo que puede ser un proceso realmente tedioso. Y aquí es donde entran en juego los frameworks de inyección de dependencia como Dagger. Su principal responsabilidad es deshacerse de todo este código repetitivo. Así que básicamente le enseñamos a Dagger cómo construir todos estos objetos y luego los crea en el momento correcto y en el orden correcto.
Así que nuestro ejemplo aquí…..se convertiría en esto. Ahora todavía tenemos un automóvil completamente funcional que puede conducir pero no tenemos que instanciar todas sus partes. En cambio, Dagger es responsable de hacer eso. Entonces, Dagger nos ayuda a deshacernos de todo el código repetitivo y al mismo tiempo cosechar los beneficios de la inyección de dependencia. Y comenzaremos a aprender sobre Dagger con más detalle en el próximo video. ¡Así que asegúrese de suscribirse al canal para no perderse ninguna de las próximas partes! Y si este video fue útil, ¡por favor deja un me gusta! ¡Cuidarse!.