Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


Dagger 2 problema sobreponiendo único proporciona el método anotado de un módulo en una biblioteca que la aplicación utiliza

Enlace del Proyecto GitHub

He hecho un proyecto en GitHub que es un modelo de la daga 2 arquitectura de mi proyecto de arquitectura real. Esta pregunta se basará en el proyecto GitHub.

He proporcionado muchos fragmentos de código en esta pregunta, sin embargo, puede ser más fácil simplemente compilar el proyecto usted mismo en Android Studio para entender el problema.

Si usted comprueba hacia fuera el código, no compilará. Vaya a AppModule.java y el comentario de ambos proporciona métodos y debe compilar.

La pregunta principal es la última línea en este post.

Https://github.com/qazimusab/Dagger2LibraryProject

Arquitectura

Tengo una biblioteca que contiene todo el código necesario para hacer la aplicación. El punto de esta arquitectura es que cada aplicación que creo en el proyecto debería ser capaz de usar la biblioteca y, a través de dagger 2, ser capaz de proporcionar diferentes implementaciones para cualquier clase o actividad que quiera en su propio módulo. En este punto sólo tengo una aplicación en este proyecto de ejemplo que utiliza la biblioteca.

El problema

Con la daga uno, tenía la misma arquitectura, y en el módulo específico de la aplicación (a diferencia del módulo de la biblioteca), pude agregar un nuevo método anotado para anular cualquier implementación que se estaba proporcionando en cualquiera de los módulos de la biblioteca Mientras

  1. El método estaba en un módulo en el módulo de aplicación
  2. El método fue anotado con @Provides
  3. El método tenía el mismo tipo de retorno que el que desea anular

Con Dagger 2, la arquitectura funciona cuando no sobrescribo ninguna de las opciones o si lo hago, cuando reemito cada una de ellas en ese módulo y retiro ese módulo de las inclusiones del módulo específico de la aplicación.

Por ejemplo, en mi proyecto, tengo una aplicación y una biblioteca.

La aplicación tiene un AppModule; La biblioteca tiene un CatModule para proporcionar un gato y CatFood, un módulo de perro para proporcionar un Dog and DogFood, y un LibraryModule para proporcionar las actividades.

CatModule.java

package com.example.qaziahmed.library.application.modules; import com.example.qaziahmed.library.classes.Cat; import com.example.qaziahmed.library.classes.CatFood; import com.example.qaziahmed.library.classes.contract.ICat; import com.example.qaziahmed.library.classes.contract.ICatFood; import javax.inject.Singleton; import dagger.Module; import dagger.Provides; /** * Created by qaziahmed on 11/23/15. */ @Module public class CatModule { @Provides @Singleton ICat provideCat() { return new Cat(); } @Provides ICatFood provideCatFood(){ return new CatFood(); } } 

DogModule.java

 package com.example.qaziahmed.library.application.modules; import com.example.qaziahmed.library.classes.Dog; import com.example.qaziahmed.library.classes.DogFood; import com.example.qaziahmed.library.classes.contract.IDog; import com.example.qaziahmed.library.classes.contract.IDogFood; import javax.inject.Singleton; import dagger.Module; import dagger.Provides; /** * Created by qaziahmed on 11/23/15. */ @Module public class DogModule { @Provides @Singleton IDog provideDog() { return new Dog(); } @Provides IDogFood provideDogFood(){ return new DogFood(); } } 

Por lo tanto, en mi módulo de aplicación, quiero proporcionar una implementación gato casa de ICat en lugar de un gato genérico y una implementación AllNaturalDogFood de IDogFood en lugar de sólo DogFood regular, a continuación, en mi AppModule agrego dos proporciona para sustituir a los

AppModule.java

 package com.example.qaziahmed.dagger2libraryproject.application; import com.example.qaziahmed.dagger2libraryproject.classes.AllNaturalDogFood; import com.example.qaziahmed.dagger2libraryproject.classes.HouseCat; import com.example.qaziahmed.library.application.modules.CatModule; import com.example.qaziahmed.library.application.modules.DogModule; import com.example.qaziahmed.library.application.modules.LibraryModule; import com.example.qaziahmed.library.classes.contract.ICat; import com.example.qaziahmed.library.classes.contract.IDogFood; import javax.inject.Singleton; import dagger.Module; import dagger.Provides; /** * Created by ogre on 2015-07-12 */ @Module(includes = { LibraryModule.class, DogModule.class, CatModule.class }) public class AppModule { @Provides @Singleton ICat provideHouseCat() { return new HouseCat(); } @Provides IDogFood provideAllNaturalDogFood(){ return new AllNaturalDogFood(); } } 

Ahora, cuando ejecuto esta configuración, este es el error que recibo:

Error: com.example.qaziahmed.library.classes.contract.ICat está enlazado varias veces: @Provides @Singleton com.example.qaziahmed.library.classes.contract.ICat com.example.qaziahmed.dagger2libraryproject.application.AppModule.provideHouseCat () @Provides @Singleton com.example.qaziahmed.library.classes.contract.ICat com.example.qaziahmed.library.application.modules.CatModule.provideCat () Error: com.example.qaziahmed.library.classes.contract. IDogFood está enlazado varias veces: @Provides com.example.qaziahmed.library.classes.contract.IDogFood com.example.qaziahmed.dagger2libraryproject.application.AppModule.provideAllNaturalDogFood () @Provides com.example.qaziahmed.library.classes.contract. IDogFood com.example.qaziahmed.library.application.modules.DogModule.provideDogFood ()

Ahora, si en AppModule.java, también agrego proporciona métodos anotados para proporcionar comida para gatos y proporcionar perro y luego eliminar CatModule.class y DogModule.class de la incluye en el módulo de aplicación, entonces funciona.

Sin embargo, toda la cuestión es cómo puedo anular un solo método proporciona en algún módulo de la biblioteca sin tener que anular cada proporciona el método anotado dentro de ese módulo específico y, a continuación, la eliminación de ese módulo de los incluye en AppModule.java

2 Solutions collect form web for “Dagger 2 problema sobreponiendo único proporciona el método anotado de un módulo en una biblioteca que la aplicación utiliza”

Intentará descifrar esta cita de la daga 2 docs:

Dagger 2 no admite anulaciones. Los módulos que reemplazan para falsificaciones de prueba simples pueden crear una subclase del módulo para emular ese comportamiento. Los módulos que utilizan anulaciones y dependen de la inyección de dependencia deben descomponerse de modo que los módulos sobrescritos se representen como una opción entre dos módulos.

En su ejemplo actual, no confía en la inyección de dependencias porque sus métodos provides* provide crean objetos nuevos sencillos para que pueda crear una subclase del módulo, sobreescribir el método de la fuente que necesita ser reemplazado y luego incluir ese nuevo módulo en Su componente.

Cuando usted tiene confianza en DI (y en realidad lo hará en alguna etapa de su proyecto) como esto:

 @Provides @Singleton ICat provideCat(IBowtie bowtie) { // 'bowtie' needs to be injected return new CatWithBowtie(Bowtie); } 

Se trata de "Módulos que utilizan anulaciones y dependen de la inyección de dependencia debe ser descompuesto", que básicamente significa: usted tiene que dividir CatModule en dos: CatModule con sólo providesCat y 'CatFoodModule' con provideCatFood() . A continuación, el componente de su aplicación que acaba de utilizar su nuevo CatWithBowtieModule lugar de CatModule .

Hay dos consejos útiles:

  1. En los proyectos de biblioteca, divida los módulos de forma que sólo haya un método provides* por módulo. Sí, suena como BS, pero esta es la única manera de facilitar la sustitución fácil más adelante en su aplicación.

  2. Por un momento vamos a fingir que la biblioteca se te da de un tercero como un JAR / AAP y ni siquiera tienen la fuente. En ese caso, no podrá volver a utilizar los módulos definidos en la lib, por lo que tendrá que crear todos ellos por usted mismo. Esto es exactamente lo que sucede con Dagger 2.

Cuando intenta usar módulos de su biblioteca en su aplicación directamente (como lo hizo) estos dos proyectos no son dos proyectos separados, sino un proyecto que se parece a dos proyectos (que son clusterf * ck estrechamente acoplado). Está bien que la aplicación dependa de la lib, pero no está bien que la lib depende de la aplicación. Se reduce a: En Dagger 2 es mejor no usar modules y components bordes cruzados (de proyecto) .

Alguien puede preguntar: "¿Qué es lo bueno de usar Dagger 2 en un lib si no puedo usar los modules / components lib en mi aplicación ?!". Bueno, usted todavía será capaz de utilizar sus modules dagger / components en sus pruebas de unidad que es el principal beneficio de usar Dagger después de todo. También si su lib está destinado a ser utilizado por otras personas puede (debe?) Proporcionar una aplicación de referencia que muestra cómo "alambre" las cosas para que los usuarios de lib sólo será capaz de copiar ese código si les conviene o al menos ver cómo para comenzar.

El problema es que su Inyección ve dos métodos que proporcionan el mismo objeto.

Si lee este enlace: http://google.github.io/dagger/ puede remediarlo nombrando a su proveedor como:

 @Provides @Named("water") 

Luego, en su Inyección, haga referencia como:

 @Inject @Named("water") 
FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.