Dagger 2 subcomponentes vs dependencias de componentes

135

El plus()método de Dagger 1 es algo que usé con bastante frecuencia en aplicaciones anteriores, por lo que entiendo situaciones en las que es posible que desee tener un subcomponente con acceso completo a los enlaces de los gráficos principales.

¿En qué situación sería beneficioso usar un dependencia de componente en lugar de una dependencia de subcomponente y por qué?

Bradley Campbell
fuente

Respuestas:

228

Dependencias de componentes: use esto cuando desee mantener dos componentes independientes.

Subcomponentes: utilícelo cuando desee mantener dos componentes acoplados.


Usaré el siguiente ejemplo para explicar las dependencias de componentes y subcomponentes . Algunos puntos que vale la pena notar sobre el ejemplo son:

  • SomeClassA1Se puede crear sin ninguna dependencia. ModuleAproporciona una instancia de a SomeClassA1través del provideSomeClassA1()método.
  • SomeClassB1no se puede crear sin SomeClassA1. ModuleBpuede proporcionar una instancia de SomeClassB1solo si una instancia de SomeClassA1se pasa como argumento al provideSomeClassB1()método.
@Module
public class ModuleA {
    @Provides
    public SomeClassA1 provideSomeClassA1() {
        return new SomeClassA1();
    }
}

@Module
public class ModuleB {
    @Provides
    public SomeClassB1 provideSomeClassB1(SomeClassA1 someClassA1) {
        return new SomeClassB1(someClassA1);
    }
}

public class SomeClassA1 {
    public SomeClassA1() {}
}

public class SomeClassB1 {
    private SomeClassA1 someClassA1;

    public SomeClassB1(SomeClassA1 someClassA1) {
        this.someClassA1 = someClassA1;
    }
}

Dagger se encargará de pasar la instancia de SomeClassA1como argumento al provideSomeClassB1()método ModuleBcuando se inicie la declaración de Componente / Subcomponente ModuleB. Necesitamos instruir a Dagger cómo cumplir con la dependencia. Esto se puede hacer utilizando la dependencia del componente o el subcomponente .

Dependencia de componentes

Tenga en cuenta los siguientes puntos en el ejemplo de dependencia de componentes a continuación:

  • ComponentBtiene que definir la dependencia a través del dependenciesmétodo de @Componentanotación.
  • ComponentAno necesita declarar ModuleB. Esto mantiene los dos componentes independientes.
public class ComponentDependency {
    @Component(modules = ModuleA.class)
    public interface ComponentA {
        SomeClassA1 someClassA1();
    }

    @Component(modules = ModuleB.class, dependencies = ComponentA.class)
    public interface ComponentB {
        SomeClassB1 someClassB1();
    }

    public static void main(String[] args) {
        ModuleA moduleA = new ModuleA();
        ComponentA componentA = DaggerComponentDependency_ComponentA.builder()
                .moduleA(moduleA)
                .build();

        ModuleB moduleB = new ModuleB();
        ComponentB componentB = DaggerComponentDependency_ComponentB.builder()
                .moduleB(moduleB)
                .componentA(componentA)
                .build();
    }
}

Subcomponente

Tenga en cuenta los siguientes puntos en el ejemplo de subcomponente:

  • Como ComponentBno ha definido la dependencia ModuleA, no puede vivir de forma independiente. Se vuelve dependiente del componente que proporcionará el ModuleA. Por lo tanto, tiene una @Subcomponentanotación.
  • ComponentAha declarado a ModuleBtravés del método de interfaz componentB(). Esto hace que los dos componentes estén acoplados. De hecho, ComponentBsolo se puede inicializar a través de ComponentA.
public class SubComponent {
    @Component(modules = ModuleA.class)
    public interface ComponentA {
        ComponentB componentB(ModuleB moduleB);
    }

    @Subcomponent(modules = ModuleB.class)
    public interface ComponentB {
        SomeClassB1 someClassB1();
    }

    public static void main(String[] args) {
        ModuleA moduleA = new ModuleA();
        ComponentA componentA = DaggerSubComponent_ComponentA.builder()
                .moduleA(moduleA)
                .build();

        ModuleB moduleB = new ModuleB();
        ComponentB componentB = componentA.componentB(moduleB);
    }
}
Praveer Gupta
fuente
44
Tengo una configuración de subcomponentes que no agrega el Módulo B al Componente A, lo que significa que el generador de componentes A no necesita el módulo B. Esto parece funcionar de la manera que esperaba permitiendo la creación de ComponentA en el inicio de la aplicación y luego instanciando m
FriendlyMikhail
2
@MikeN - ¿Puedes destacar cómo puedes deshacerte de ModuleB en ComponentA? Puedo deshacerme de ModuleB en ComponentA solo si proporciono diferentes ámbitos en ComponentA y ComponentB.
Praveer Gupta
1
Tienes razón, mi configuración funciona porque están en diferentes ámbitos. disculpas
FriendlyMikhail
2
" SomeClassB1depende de SomeClassA1. ComponentAtiene que definir explícitamente la dependencia". ==> ¿ha querido decir " ComponentBtiene que definir explícitamente la dependencia"?
Tar
1
De manera similar a lo que señaló @Tar, entiendo que en " SomeClassB1depende de SomeClassA1. ComponentANo necesita definir explícitamente la dependencia". querías decir " ComponentBno es necesario que defina explícitamente la dependencia".
Sebas LG
45

De acuerdo con la documentación :

Component Dependencyle da acceso solo a los enlaces expuestos como métodos de provisión a través de las dependencias de los componentes, es decir, solo tiene acceso a los tipos que se declaran en padre Component.

SubComponentte da acceso a todo gráfico de enlace desde su padre cuando se declara, es decir, tiene acceso a todos los objetos declarados en su Modules.

Digamos Vamos, usted tiene una ApplicationComponentque contiene toda Androidla materia relacionada ( LocationService, Resources, SharedPreference, etc.). También desea tener su lugar DataComponentdonde administra las cosas para la persistencia junto con el WebServicemanejo de las API. Lo único que te falta DataComponentes en Application Contextqué reside ApplicationComponent. La forma más sencilla de obtener una Contextdesde DataComponentsería una dependencia ApplicationComponent. Debe asegurarse de tener una Contextdeclaración explícita ApplicationComponentporque solo tiene acceso a las cosas declaradas. En este caso, no hay trabajo manual, lo que significa que no necesita especificar Submodulesen el padre Componenty agregar explícitamente su submódulo a un módulo padre como:

MySubcomponent mySubcomponent = myComponent.plus(new ChildGraphModule("child!")); // No need!

Consideremos ahora que el caso en el que desea inyectar WebServicedesde DataComponenty LocationServiceentre ApplicationComponenten sus Fragmentque se une utilizando la @Submodule pluscaracterística anterior. Lo bueno aquí es que el componente al que está vinculando ( ApplicationComponent) no necesita exponer WebServiceni LocationServiceporque tiene acceso a todo el gráfico de inmediato.

Eugene
fuente
2
Si entiendo correctamente, no hay una interfaz llamada @Submodule. ¿Es un error tipográfico?
Islam Salah
Me gusta cómo esto usa un ejemplo de la vida real para mostrar la diferencia. Sin embargo, esto es más confuso que leer los documentos. Sería útil tener menos classescomo ejemplos y más imágenes para ilustrar el punto exacto.
sudocoder
18

Aquí está el ejemplo de código con captura de pantalla para una mejor comprensión de Componente y Subcomponente:

Componente: ingrese la descripción de la imagen aquí

  1. AppComponent contiene dos declaraciones.
  2. AppComponent se inicializa en la clase de aplicación.
  3. HomeActivityComponent depende de AppComponent.
  4. En HomeActivity sobre la inicialización de DaggerHomeActivityComponent, estoy dando el objeto AppComponent como composición.

Subcomponente:

ingrese la descripción de la imagen aquí

  1. AppComponent contiene SubComponent o SubComponents.
  2. AppComponent se inicializa en la clase de aplicación.
  3. El subcomponente no sabe acerca de su componente principal. Que solo proporciona sus propias dependencias al incluir el Módulo.
  4. En HomeActivity estoy inyectando un subcomponente usando su componente padre.

Y el diagrama pictórico: ingrese la descripción de la imagen aquí

Fuente: enlace

0xAliHn
fuente
¿No tendría más sentido el diagrama si el subcomponente incluyera el componente de aplicación?
Florian Walther
1

Otra cosa de la que no me había dado cuenta hasta ahora es que:

  • Una @Subcomponentinstancia tiene exactamente un componente principal (aunque diferentes componentes pueden crear una instancia de ese mismo@Subcomponent y ser el principal de esa instancia)
  • A @Componentpuede tener cero, uno o muchos componentes "primarios" declarados a través de dependencias de componentes
arekolek
fuente
1
Probablemente en el segundo caso no es correcto decir que '@Component' puede tener ... padre (s). Más bien, '@Component' no tiene padres, pero otros pueden depender de eso (simplemente usarlo) a través de las dependencias de los componentes.
demaksee 01 de
@demaksee No lo sé, me parece que si traza la jerarquía de sus componentes, obtendrá DAG, y creo que es una forma estándar de referirse a esta relación como padre-hijo en el contexto gráfico. Si estamos hablando del funcionamiento interno de Dagger, entonces supongo que podría no ser la palabra correcta.
arekolek 01 de