Dagger 2: Inyectar el parámetro introducido por el usuario en el objeto

Digamos que tengo una clase Util que tiene en un objeto – una instancia de la clase Validator .

Puesto que quiero evitar instanciar la clase Validator dentro de Util, lo paso a través de un constructor:

public class Utils { @Inject public Util(Validator validator) { } } 

Tengo un módulo que proporciona la instancia Validator:

 @Provides @Singleton PhoneNumberUtil provideValidator() { return Validator.getInstance(); } 

Y una instancia de la clase Util:

 @Provides Util provideUtil(Validator validator) { return new Utils(validator); } 

Tengo un componente cableado que me daría una instancia de Util:

 Util getUtil() 

Así que dentro de mi actividad, podría llamarlo así:

 Util myUtil = getComponent.getUtil(); 

Todo eso funciona bien – myUtil tiene una instancia adecuada de la clase Validator cuando se instancia.

Ahora quiero pasar en una variable String nombre dirección (que es la entrada del usuario a través de una interfaz de usuario). Quiero cambiar el constructor así que paso en una instancia de Validator y el usuario inputted Cadena:

 @Inject public Util(Validator validator, String address) { } 

Simplemente no puedo obtener mi cabeza alrededor de cómo pasar ese segundo parámetro. ¿Puede alguien decirme cómo?

Idealmente, quiero instanciar Util como:

 Util myUtil = getComponent.getUtil(txtAddress.getText()); 

Tuve la misma pregunta que tú cuando empecé a buscar Dagger 2 hace un par de semanas. Encontré información sobre esto (y la mayoría de otros temas relacionados con Dagger 2) difícil de conseguir, así que espero que esto ayude!

La respuesta más básica es que no se puede. Lo que usted está buscando es algo que se llama inyección asistida , y no es parte de Daga 2. Algunos otros marcos de inyección de dependencia (DI), como Guice , ofrecen esta característica, por lo que podría mirar en ellos. Por supuesto, todavía hay maneras de hacer lo que quieres hacer usando Daga 2.

Fábricas fábricas fábricas

La forma estándar de hacer lo que se desea hacer en combinación con DI es utilizando el patrón de fábrica. Básicamente, se crea una clase de fábrica inyectable que toma parámetros de tiempo de ejecución como address como argumentos a los métodos de creación de objetos que proporciona.

En su caso, necesitaría un UtilFactory en el que Dagger 2 inyecta un Validator al instante y que ofrece un método create(String address) que crea instancias de Util . UtilFactory debe mantener una referencia a la instancia inyectada de Validator para que tenga todo lo necesario para crear una instancia de Util en el método create .

El código de retorcimiento de muchas de estas fábricas puede ser engorroso. Usted debe definitivamente echar un vistazo a AutoFactory , que alivia parte de la carga. La inyección asistida de Guice parece funcionar bastante similar a Dagger 2 + AutoFactory (aunque con azúcar sintáctico aún más agradable).

Más módulos / componentes

Dudo que esto sea algo que le gustaría hacer en este caso, pero podría crear un módulo que proporcione la dirección (e instanciar un nuevo componente). No es necesario crear una nueva clase @Module para cada dirección posible. En su lugar, sólo puede pasar la dirección como un argumento al constructor del módulo.

No estoy seguro si esto es un anti-patrón o no. Para mí, esto parece ser una ruta aceptable en algunos casos, pero sólo cuando está utilizando la misma dirección por ejemplo para la inicialización de "muchos" objetos. Definitivamente no desea instanciar un nuevo componente y un nuevo modelo para cada objeto que requiere inyección. No es eficiente, y si usted no es cuidadoso usted terminará para arriba con un código más boilerplate que sin daga.

No (siempre) usar DI: Inyectables versus nuevos

Algo que me resultó inmensamente útil cuando aprendí acerca de los marcos DI fue la comprensión de que el uso de un marco DI no significa que usted tiene que DI para inicializar todos sus objetos. Como regla general: inyecte objetos que conozca en tiempo de compilación y que tengan relaciones estáticas con otros objetos; No inyecte información de tiempo de ejecución.

Creo que este es un buen post sobre el tema. Introduce el concepto de "nuevos" e "inyectables".

  • Inyectables son las clases cerca de la raíz de su gráfico DI. Las instancias de estas clases son el tipo de objetos que usted espera que su marco DI proporcione e inyecte. Los objetos de tipo de servicio o de servicio son ejemplos típicos de inyectables.
  • Los objetos nuevos son objetos en las franjas de su gráfico DI, o que no son realmente parte de su gráfico DI en absoluto. Integer , Address etc. son ejemplos de elementos nuevos.

Hablando en términos generales, los objetos nuevos son objetos pasivos, y no tiene sentido inyectarse o burlarse de ellos. Por lo general contienen los "datos" que están en su aplicación y que sólo está disponible en tiempo de ejecución (por ejemplo, su dirección). Los objetos nuevos no deben guardar referencias a los inyectables o viceversa (algo que el autor del post denomina "inyectable / nueva-separación").

En realidad, he encontrado que no siempre es fácil o posible hacer una distinción clara entre inyectables y nuevos. Sin embargo, creo que son buenos conceptos para usar como parte de su proceso de pensamiento. ¡Definitivamente piensa dos veces antes de agregar otra fábrica a tu proyecto!

En su caso, creo que tendría sentido tratar Util como un inyectable. Esto significa que la dirección no debe formar parte de la clase Util . Si desea utilizar la instancia de Util para, por ejemplo, validating / … addresses, simplemente pase la dirección que desea validar como argumento al método de validación / ….

Cuando inicie el módulo, puede pasar algunos parámetros como este:

 public NetServiceModule(String baseUrl, boolean isLogEnabled, CookieJar cookieJar) { this.mBaseUrl = baseUrl; this.mIsLogEnabled = isLogEnabled; this.mCookieJar = cookieJar; } 

Y luego obtenga el componente en "Clase de contenedor":

 NetServiceComponent component = DaggerNetServiceComponent.builder() .netServiceModule(new NetServiceModule(baseUrl, mIsLogEnabled, cookieJar)) .build(); component.inject(this); 

Con Proporciona el método para proporcionar Inyección que genera por algunos parámetros si es necesario:

 @Provides Retrofit provideRetrofit(OkHttpClient httpClient, GsonConverterFactory gsonConverterFactory, NetCallAdapterFactory netCallAdapterFactory) { return new Retrofit.Builder() .client(httpClient) .baseUrl(mBaseUrl) .addConverterFactory(gsonConverterFactory) .addCallAdapterFactory(netCallAdapterFactory) .build(); } 

Puede cambiar el constructor de componentes para inyectar instancias. Consulte: https://google.github.io/dagger/users-guide#binding-instances

En su caso, puede llamar a:

 Util myUtil = DaggerMyComponent.builder().withAddress(txtAddress.getText()).build().getComponent().getUtil(); 

Si MyComponent se define como:

 @Component(modules = UtilModule.class) interface MyComponent{ MyComponent getComponent(); @Component.Builder interface Builder { @BindsInstance Builder withAddress(@Address String address); MyComponent build(); } } 

Y UtilModule:

 @Module class UtilModule{ @Provides Util getModule(Validator validator, @Address String address){ return new Util(validator, address); } } 

Validador, por supuesto, se debe proporcionar con @Inject anotado constructor o @Provides un método anotado en una clase de módulo pasó a los módulos de MyComponent en la anotación @Component.

  • Vista de Google Street + inclinación del dispositivo
  • Android: java.lang.Throwable: setStateLocked
  • Configuración de la codificación para una entidad multiparte
  • GetGSMSignalStrength () devuelve siempre 99
  • Manejo de InterruptedException mientras espera una señal de salida (error en Android?)
  • Org.json.JSONException: Objeto no terminado en el carácter 14
  • Configuración del color del encabezado en el nuevo Material DatePicker
  • Almacenamiento de la clave con KeyStore en Android
  • Renderización de Android OpenGLES con C ++ y Java
  • ¿Por qué no podemos usar arrays en lugar de varargs?
  • Android Annotations - Inyección de una lista de tipo superclase
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.