La inyección de dependencias (DI) es una técnica muy utilizada en programación y adecuada para el desarrollo de Android. Si sigues los principios de la DI, sentarás las bases para una buena arquitectura de apps.
Implementar la inyección de dependencias te proporciona las siguientes ventajas:
- Reutilización de código
- Facilidad de refactorización
- Facilidad de prueba
Aspectos básicos de la inyección de dependencias
Antes de analizar específicamente la inyección de dependencias en Android, en esta página se proporciona una descripción más general de cómo funciona la inyección de dependencias.
¿Qué es la inyección de dependencias?
Las clases suelen requerir referencias a otras clases. Por ejemplo, una clase Car
podría necesitar una referencia a una clase Engine
. Estas clases se llaman dependencias y, en el ejemplo, la clase Car
necesita una instancia de la clase Engine
, de la que depende para ejecutarse.
Una clase puede obtener un objeto que necesita de tres maneras distintas:
- La clase construye la dependencia que necesita. En el ejemplo anterior,
Car
crea e inicializa su propia instancia deEngine
. - La toma de otro lugar. Algunas API de Android, como los métodos get de
Context
ygetSystemService()
, funcionan de esta manera. - La recibe como parámetro. La app puede proporcionar estas dependencias cuando se construye la clase o pasarlas a las funciones que necesitan cada dependencia. En el ejemplo anterior, el constructor
Car
recibeEngine
como parámetro.
La tercera opción es la inyección de dependencias. Con este enfoque, tomas las dependencias de una clase y las proporcionas en lugar de hacer que la instancia de la clase las obtenga por su cuenta.
Por ejemplo: Sin inyección de dependencias, la representación de un Car
que crea su propia dependencia Engine
se ve así en el código:
class Car { private val engine = Engine() fun start() { engine.start() } } fun main(args: Array) { val car = Car() car.start() }
class Car { private Engine engine = new Engine(); public void start() { engine.start(); } } class MyApp { public static void main(String[] args) { Car car = new Car(); car.start(); } }

Este no es un ejemplo de inyección de dependencias, porque la clase Car
está construyendo su propio Engine
, lo que puede ser problemático debido a lo siguiente:
Car
yEngine
están estrechamente vinculados: una instancia deCar
usa un tipo deEngine
, y no se pueden utilizar subclases ni implementaciones alternativas con facilidad. Si elCar
construyera su propioEngine
, tendrías que crear dos tipos deCar
en lugar de solo reutilizar el mismoCar
para motores de tipoGas
yElectric
.La dependencia estricta de
Engine
hace que las pruebas sean más difíciles.Car
usa una instancia real deEngine
, lo que impide utilizar un doble de prueba y modificarEngine
para diferentes casos de prueba.
¿Cómo se ve el código con la inyección de dependencias? En lugar de que las diferentes instancias de Car
construyan su propio objeto Engine
durante la inicialización, cada una recibe un objeto Engine
como parámetro en su constructor:
class Car(private val engine: Engine) { fun start() { engine.start() } } fun main(args: Array) { val engine = Engine() val car = Car(engine) car.start() }
class Car { private final Engine engine; public Car(Engine engine) { this.engine = engine; } public void start() { engine.start(); } } class MyApp { public static void main(String[] args) { Engine engine = new Engine(); Car car = new Car(engine); car.start(); } }

La función main
usa Car
. Debido a que Car
depende de Engine
, la app crea una instancia de Engine
y, luego, la usa para construir una instancia de Car
. Los beneficios de este enfoque basado en DI son los siguientes:
Reutilización de
Car
. Puedes pasar diferentes implementaciones deEngine
aCar
. Por ejemplo, puedes definir una nueva subclase deEngine
, llamadaElectricEngine
, para utilizar conCar
. Si usas DI, solo debes pasar una instancia de la subclase actualizada deElectricEngine
yCar
seguirá funcionando sin más cambios.Prueba fácil de
Car
. Puedes pasar dobles de prueba para probar diferentes situaciones. Por ejemplo, puedes crear un doble de prueba deEngine
, llamadoFakeEngine
, y configurarlo para diferentes pruebas.
Existen dos formas principales de realizar la inyección de dependencias en Android:
Inyección de constructor. Esta es la manera descrita anteriormente. Pasas las dependencias de una clase a su constructor.
Inyección de campo (o inyección de método set). El sistema crea instancias de ciertas clases de framework de Android, como actividades y fragmentos, por lo que no es posible implementar la inyección de constructor. Con la inyección de campo, se crean instancias de dependencias después de crear la clase. El código se vería así:
class Car { lateinit var engine: Engine fun start() { engine.start() } } fun main(args: Array) { val car = Car() car.engine = Engine() car.start() }
class Car { private Engine engine; public void setEngine(Engine engine) { this.engine = engine; } public void start() { engine.start(); } } class MyApp { public static void main(String[] args) { Car car = new Car(); car.setEngine(new Engine()); car.start(); } }
Inyección de dependencias automatizada
En el ejemplo anterior, creaste, proporcionaste y administraste por tu cuenta las dependencias de las diferentes clases, sin recurrir a una biblioteca. Esto se denomina inyección de dependencias a mano o inyección de dependencias manual. En el ejemplo de Car
, solo había una dependencia, pero, si hay varias dependencias y clases, la inyección manual puede resultar más tediosa. Además, la inyección de dependencias manual presenta varios problemas:
En el caso de aplicaciones grandes, tomar todas las dependencias y conectarlas correctamente puede requerir una gran cantidad de código estándar. En una arquitectura de varias capas, para crear un objeto en una capa superior, debes proporcionar todas las dependencias de las capas que se encuentran debajo de ella. Por ejemplo, para construir un automóvil real, es posible que necesites un motor, una transmisión, un chasis y otras piezas; a su vez, el motor necesita cilindros y bujías.
Cuando no puedes construir dependencias antes de pasarlas (por ejemplo, si usas inicializaciones diferidas o solicitas permisos para objetos en los flujos de tu app), necesitas escribir y conservar un contenedor personalizado (o un grafo de dependencias) que administre las dependencias en la memoria desde el principio.
Hay bibliotecas que resuelven este problema automatizando el proceso de creación y provisión de dependencias. Se dividen en dos categorías:
Soluciones basadas en reflexiones que conectan las dependencias durante el tiempo de ejecución.
Soluciones estáticas que generan el código para conectar las dependencias durante el tiempo de compilación.
Dagger es una biblioteca de inserción de dependencias popular para Java, Kotlin y Android que mantiene Google. Dagger facilita el uso de la DI en tu app mediante la creación y administración del grafo de dependencias. Proporciona dependencias totalmente estáticas y en tiempo de compilación que abordan muchos de los problemas de desarrollo y rendimiento de las soluciones basadas en reflexiones, como Guice.
Alternativas a la inserción de dependencias
Una alternativa a la inserción de dependencias es usar un localizador de servicios. El patrón de diseño del localizador de servicios también mejora el desacoplamiento de clases de las dependencias concretas. En este procedimiento, creas una clase conocida como localizador de servicios que, a su vez, crea y almacena dependencias, y luego proporciona esas dependencias a pedido.
object ServiceLocator { fun getEngine(): Engine = Engine() } class Car { private val engine = ServiceLocator.getEngine() fun start() { engine.start() } } fun main(args: Array) { val car = Car() car.start() }
class ServiceLocator { private static ServiceLocator instance = null; private ServiceLocator() {} public static ServiceLocator getInstance() { if (instance == null) { synchronized(ServiceLocator.class) { instance = new ServiceLocator(); } } return instance; } public Engine getEngine() { return new Engine(); } } class Car { private Engine engine = ServiceLocator.getInstance().getEngine(); public void start() { engine.start(); } } class MyApp { public static void main(String[] args) { Car car = new Car(); car.start(); } }
El patrón del localizador de servicios se diferencia de la inyección de dependencias en la forma en que se consumen los elementos. Con el patrón del localizador de servicios, las clases tienen el control y solicitan que se inyecten objetos. Con la inyección de dependencias, la app tiene el control e inyecta los objetos solicitados de manera proactiva.
En comparación con la inyección de dependencias:
La colección de dependencias que requiere un localizador de servicios hace que el código sea más difícil de probar, ya que todas las pruebas tienen que interactuar con el mismo localizador de servicios global.
Las dependencias se codifican en la implementación de la clase, no en la superficie de la API. De esta manera, es más difícil saber qué necesita una clase del exterior. Por ese motivo, los cambios en
Car
o las dependencias disponibles en el localizador de servicios pueden provocar que fallen las referencias, y así generar errores durante el tiempo de ejecución o en las pruebas.Administrar los ciclos de vida de los objetos es más difícil si no quieres establecer alcances que abarquen el ciclo de vida completo de toda la app.
Cómo usar Hilt en tu app para Android
Hilt es la biblioteca de Jetpack recomendada para la inserción de dependencias en Android. Hilt establece una forma estándar de usar la inserción de dependencias en tu aplicación, ya que proporciona contenedores para cada clase de Android en tu proyecto y administra automáticamente sus ciclos de vida.
Hilt se basa en la popular biblioteca de inserción de dependencias Dagger y se beneficia de la corrección en tiempo de compilación, el rendimiento del entorno de ejecución, la escalabilidad y la compatibilidad con Android Studio que proporciona.
Para obtener más información sobre Hilt, consulta Inserción de dependencias con Hilt.
Conclusión
La inyección de dependencias le proporciona a tu app las siguientes ventajas:
Reutilización de clases y desacoplamiento de dependencias: Es más fácil cambiar las implementaciones de una dependencia. Se mejora la reutilización de código debido a la inversión del control, y las clases ya no controlan cómo se crean sus dependencias, sino que funcionan con cualquier configuración.
Facilidad de refactorización: Las dependencias se convierten en una parte verificable de la superficie de la API, por lo que pueden verificarse durante el tiempo de creación de objetos o el tiempo de compilación en lugar de ocultarse como detalles de implementación.
Facilidad de prueba: Una clase no administra sus dependencias, por lo que, cuando la pruebas, puedes pasar diferentes implementaciones para probar todos los casos diferentes.
Para comprender por completo los beneficios de la inserción de dependencias, debes probarla de forma manual en tu app, como se muestra en la sección Inserción de dependencias manual.
Recursos adicionales
Para obtener más información sobre la inyección de dependencias, consulta los siguientes recursos adicionales.
Ejemplos
Mir 2: Return of the King es un juego para dispositivos móviles de alta calidad con la IP de Legend autorizado por Actoz Soft y desarrollado por HK ZHILI YAOAN LIMITED con el motor de juego Unity. Este juego no solo recrea a la perfección los Wuthering Waves es un juego de rol de acción de alta fidelidad desarrollado por Kuro Games.
Optimizar el consumo de energía es muy importante para ofrecer de forma sostenible una experiencia del usuario premium en sesiones de juego largas. Android Godot Engine es un popular motor de juego multiplataforma de código abierto con una compatibilidad sólida con Android. Godot se puede usar para crear juegos de prácticamente cualquier género y es capaz de renderizar gráficos en 2D y 3D. La versión 4 El framework de rendimiento dinámico (ADPF) de Android es una herramienta potente de Google para desarrolladores que desean optimizar el rendimiento de sus aplicaciones. A través de sus APIs térmicas, ADPF proporciona información en tiempo real sobre NCSoft Lineage W es un juego de rol multijugador masivo en línea (MMORPG) desarrollado por NCSoft. Este juego hereda el legado del juego original de Lineage W y ofrece un entorno en el que los jugadores de todo el mundo pueden cooperar y competir a La mejora del rendimiento y la administración térmica es fundamental para desarrollar juegos exitosos en Android. Tradicionalmente, los desarrolladores tenían que manejar estos problemas disminuyendo la fidelidad del juego o optimizando aún más el Call of Duty: Warzone Mobile es un juego de acción en primera persona de la popular franquicia Call of Duty. La materialización móvil del juego de consola y de PC, que es muy popular, aprovecha las APIs de bajo nivel para dispositivos móviles con el Summoners War: Chronicles es un MMORPG para dispositivos móviles del desarrollador de juegos surcoreano Com2uS que se lanzó a nivel mundial en marzo de 2023. Hasta la fecha, Summoners War ha ganado más de USD 2,700 millones con más de 180 millones de Summoners War: Chronicles US(WW) y KR de Com2uS usan exclusivamente Vulkan para la renderización en Android, con mejoras de rendimiento de hasta un 30%. Vulkan es una API multiplataforma moderna de gráficos 3D diseñada para minimizar la abstracción Ares: Rise of Guardians es un MMORPG de ciencia ficción de dispositivo móvil a PC desarrollado por Second Dive, un estudio de juegos con sede en Corea, conocido por su experiencia en el desarrollo de series de RPG de acción. Kakao Games publicó el Cat Daddy Games es un estudio de propiedad plena de 2K con sede en Kirkland, Washington y el desarrollador de NBA 2K Mobile.
El equipo quería mejorar la calidad y estabilidad generales de sus juegos, en particular, reduciendo los errores de Devsisters es un desarrollador y publicador de juegos para dispositivos móviles a nivel mundial que produce juegos casuales basados en la IP de Cookie Run. Sus juegos más populares incluyen Cookie Run: OvenBreak (salada de videojuegos para correr) y NEW STATE Mobile es un juego de batalla masiva de Krafton que se lanzó en noviembre de 2021 en todo el mundo y alcanzó más de 45 millones de descargas en el primer mes de su lanzamiento. KRAFTON, Inc. es un colectivo de estudios independientes de Con sede en Polonia, Spokko es un grupo de creadores ambiciosos que trabajan con IP muy exigentes. Aunque forma parte de la familia CD PROJEKT, Spokko es una empresa independiente que trasladó el gran mundo de The Witcher: Monster Slayer a los Cat Daddy Games es un estudio de propiedad plena 2K con sede en Kirkland, Washington. Los equipos detrás de las series NBA 2K Mobile, NBA SuperCard y WWE SuperCard buscaban una solución con el fin de mejorar la calidad general de sus juegos para los Unreal Engine es un motor de juego desarrollado por Epic Games, que brinda a los creadores de todas las industrias libertad y control para ofrecer entretenimiento de vanguardia, visualizaciones atractivas y mundos virtuales envolventes. Algunos Electronic Arts (EA) es una empresa de juegos con sede en California, EE.UU. Produce una gran variedad de juegos de diferentes géneros, como deportes, acción, carreras y simulación. El estudio de desarrollo de EA, Firemonkeys, es más conocido como el Con sede en Varsovia, Polonia, la empresa desarrolladora de juegos CD Projekt RED (CDPR) rediseñó su minijuego de The Witcher 3, GWENT: The Witcher Card Game, para lanzarlo como título independiente y gratuito en Google Play en marzo de 2020.
Debido La empresa desarrolladora RV AppStudios, cuya sede está en EE.UU., cuenta con más de 200 millones de descargas hasta la fecha de los juegos casuales, las apps educativas para niños y las apps de utilidad que conforman su cartera. Siendo uno de los En el año 2000, Gameloft se creó gracias a la pasión por los juegos y un deseo de llevarlos a los jugadores de todo el mundo. Fue pionera en el desarrollo de apps para dispositivos móviles y ahora tiene una cartera de más de 190 juegos. Muchos de los Durante más de 20 años, Gameloft ha creado experiencias de juego innovadoras para plataformas digitales, desde juegos para dispositivos móviles hasta títulos multiplataforma de PC y consola. Además de sus propias franquicias establecidas, Gameloft El equipo de desarrolladores de videojuegos con sede en Moscú, Pixonic, se enorgullece de aprovechar todas las oportunidades para actualizar las apps para dispositivos móviles y llegar a un público más amplio de gamers. Uno de los títulos más Gameloft siempre se esfuerza por ser uno de los primeros desarrolladores en publicar juegos en el hardware portátil más reciente para brindarles a los gamers experiencias emocionantes dondequiera que estén. Por eso, Gameloft sabía que ChromeOS era elMir 2 mejora el rendimiento de renderización con la biblioteca de Frame Pacing.
Kuro Games reduce el consumo de energía en un 9.68% con el generador de perfiles de energía de Android Studio y ODPM para Wuthering Waves
Optimización de Vulkan de Godot Engine para Android
Cómo comenzar a usar el Framework de rendimiento dinámico de Android (ADPF) en Unreal Engine
NCSoft Lineage W mejora el rendimiento sostenido y previene los límites térmicos mediante el uso de ADPF
MediaTek mejora el rendimiento dinámico de los SoCs de Android
Call of Duty Warzone Mobile usa Vulkan para mejorar los gráficos
Com2uS - Google Play Juegos para PC
Com2uS usa Vulkan para obtener mejores gráficos
Kakao Games aumentó la estabilidad de FPS en un 96% gracias a la adaptabilidad para Android
2K reduce la tasa de ANR en un 35% con Android Game Development Kit
Cookie Run: OvenBreak ahorra más de USD 200,000 en costos de CDN con Play Asset Delivery
NEW STATE para dispositivos móviles reduce el uso de GPU en un 22% con el Inspector de GPU de Android
The Witcher: Monster Slayer mejora su alcance con Android Performance Tuner
2K entrega gráficos de mayor calidad con Play Asset Delivery
"AGDE es increíble" para el desarrollo de Android con Unreal Engine
Firemonkeys redujo el tiempo de desarrollo y depuración con AGDE
CD Projekt RED: Reduce el tamaño de las actualizaciones en un 90% y aumenta las tasas de actualización en un 10% con Play Asset Delivery
RV AppStudios mejora la retención de usuarios con Google Play Asset Delivery
Gameloft adquiere un 10% más de usuarios nuevos con Google Play Asset Delivery
Gameloft reduce el consumo de energía de los dispositivos en un 70%, lo que aumenta el tiempo de juego en un 35% con la API de Game Mode
Pixonic aumentó la participación en un 25% en ChromeOS mediante la optimización para pantallas grandes
Gameloft obtiene 9 veces más ingresos gracias a la optimización para ChromeOS