Sous-composants de Dagger 2 vs dépendances de composants

135

La plus()méthode de Dagger 1 est quelque chose que j'ai utilisé assez souvent dans les applications précédentes, donc je comprends les situations où vous pourriez vouloir avoir un sous-composant avec un accès complet aux liaisons des graphes parents.

Dans quelle situation serait-il avantageux d'utiliser une dépendance de composant au lieu d'une dépendance de sous - composant et pourquoi?

Bradley Campbell
la source

Réponses:

228

Dépendances de composants - Utilisez cette option lorsque vous souhaitez conserver deux composants indépendants.

Sous-composants - Utilisez cette option lorsque vous souhaitez conserver deux composants couplés.


J'utiliserai l'exemple ci-dessous pour expliquer les dépendances et les sous- composants des composants . Quelques points à noter à propos de l'exemple sont:

  • SomeClassA1peut être créé sans aucune dépendance. ModuleAfournit et instance de SomeClassA1via la provideSomeClassA1()méthode.
  • SomeClassB1ne peut pas être créé sans SomeClassA1. ModuleBne peut fournir une instance de SomeClassB1que si une instance de SomeClassA1est passée en argument à provideSomeClassB1()method.
@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 chargera de transmettre l'instance de SomeClassA1comme argument à la provideSomeClassB1()méthode ModuleBchaque fois que la déclaration du composant / sous-composant ModuleBest initialisée. Nous devons indiquer à Dagger comment remplir la dépendance. Cela peut être fait soit en utilisant la dépendance de composant ou sous- composant .

Dépendance des composants

Notez les points suivants dans l'exemple de dépendance de composant ci-dessous:

  • ComponentBdoit définir la dépendance via la dependenciesméthode sur l' @Componentannotation.
  • ComponentAn'a pas besoin de déclarer ModuleB. Cela maintient les deux composants indépendants.
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();
    }
}

Sous-composant

Notez les points suivants dans l'exemple SubComponent:

  • Comme ComponentBn'a pas défini la dépendance ModuleA, il ne peut pas vivre de manière indépendante. Il devient dépendant du composant qui fournira le ModuleA. Par conséquent, il a un@Subcomponent annotation.
  • ComponentAa déclaré ModuleBvia la méthode d'interface componentB(). Cela rend les deux composants couplés. En fait, ComponentBne peut être initialisé que via 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
la source
4
J'ai une configuration de sous-composant qui n'ajoute pas le module B à ComponentA, ce qui signifie alors que le constructeur de componentA n'a pas besoin de moduleB. Cela semble fonctionner comme je m'attendais à permettre la création de ComponentA au démarrage de l'application, puis à instancier m
FriendlyMikhail
2
@MikeN - Pouvez-vous souligner comment vous pourriez vous débarrasser de ModuleB sur ComponentA? Je ne peux me débarrasser de ModuleB sur ComponentA que si je fournis des portées différentes sur ComponentA et ComponentB.
Praveer Gupta
1
Vous avez raison, ma configuration fonctionne car ils sont sur des portées différentes. excuses.
FriendlyMikhail
2
" SomeClassB1dépend de SomeClassA1. ComponentAdoit définir explicitement la dépendance." ==> avez-vous voulu dire " ComponentBdoit définir explicitement la dépendance"?
Tar
1
De la même manière que @Tar a souligné, je comprends que dans " SomeClassB1dépend de SomeClassA1. N'a ComponentApas besoin de définir explicitement la dépendance." vous vouliez dire "il ComponentBn'est pas nécessaire de définir explicitement la dépendance".
Sebas LG
45

Selon la documentation :

Component Dependency vous donne accès uniquement aux liaisons exposées en tant que méthodes de mise à disposition via les dépendances de composants, c'est-à-dire que vous n'avez accès qu'aux types déclarés dans le parent Component .

SubComponentvous donne un accès à l' ensemble du graphe de liaison depuis son parent lorsqu'il est déclaré, c'est-à-dire que vous avez un accès à tous les objets déclarés dans son Modules.

Le mot Let, vous avez un ApplicationComponentcontenant toutes Androidchoses connexes ( LocationService, Resources, SharedPreference, etc.). Vous voulez également avoir votre DataComponentendroit où vous gérez les choses pour la persistance et WebServicepour gérer les API. La seule chose qui vous manque, DataComponentc'est de savoir Application Contextqui réside ApplicationComponent. Le moyen le plus simple d'obtenir un Contextde DataComponentserait une dépendance sur ApplicationComponent. Vous devez vous assurer que vous avez un Contextexplicitement déclaré dans ApplicationComponentcar vous n'avez accès qu'aux éléments déclarés. Dans ce cas, il n'y a pas de travail manuel, ce qui signifie que vous n'avez pas besoin de spécifier Submodulesdans parent Componentet d'ajouter explicitement votre sous-module à un module parent comme:

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

Maintenant , considérons ce cas où vous voulez injecter à WebServicepartir DataComponentet à LocationServicepartir ApplicationComponentdans votre Fragmentqui se fixe à l' aide de la @Submodule plusfonction ci - dessus. Ce qui est cool ici, c'est que le composant auquel vous liez ( ApplicationComponent) n'a pas besoin d'exposer WebServiceni LocationServiceparce que vous avez accès à l'ensemble du graphique tout de suite.

Eugène
la source
2
Si je comprends bien, aucune interface n'est appelée @Submodule. Est-ce une faute de frappe?
Islam Salah
J'aime la façon dont cela utilise un exemple réel pour montrer la différence. Cependant, cela est plus déroutant que la lecture de la documentation. Il serait utile d'avoir moins classesd'exemples et plus d'images pour illustrer le point exact.
sudocoder le
18

Voici l'exemple de code avec capture d'écran pour plus de compréhension de Component et SubComponent:

Composant: entrez la description de l'image ici

  1. AppComponent contient deux déclarations.
  2. AppComponent s'initialise dans la classe App.
  3. HomeActivityComponent dépend de AppComponent.
  4. Dans HomeActivity lors de l'initialisation de DaggerHomeActivityComponent, je donne l'objet AppComponent comme composition.

Sous-composant:

entrez la description de l'image ici

  1. AppComponent contient SubComponent ou SubComponents.
  2. AppComponent s'initialise dans la classe App.
  3. SubComponent ne connaît pas son ParentComponent. Cela ne fournit que ses propres dépendances en incluant Module.
  4. Dans HomeActivity, j'injecte SubComponent en utilisant son Parent Component.

Et le diagramme pictural: entrez la description de l'image ici

Source: lien

0xAliHn
la source
Le diagramme n'aurait-il pas plus de sens si le sous-composant renfermait l'AppComponent?
Florian Walther
1

Une autre chose dont je n'avais pas vraiment conscience jusqu'à présent, c'est que:

  • Une @Subcomponentinstance a exactement un composant parent (bien que différents composants puissent l'instancier @Subcomponentet être le parent de cette instance)
  • A @Componentpeut avoir zéro, un ou plusieurs composants «parents» déclarés via les dépendances de composants
Arekolek
la source
1
Probablement dans le second cas, il n'est pas correct de dire que '@Component' peut avoir ... parent (s). Au contraire, «@Component» n'a pas de parents, mais d'autres peuvent en dépendre (utilisez-le simplement) via les dépendances de composants.
demaksee
@demaksee Je ne sais pas, il me semble que si vous cartographiez votre hiérarchie de composants, vous obtiendrez DAG, et je pense que c'est une manière standard de désigner cette relation comme parent-enfant dans un contexte de graphique. Si nous parlons du fonctionnement interne de Dagger, alors je suppose que ce n'est peut-être pas le bon mot.
arekolek