Субкомпоненты Dagger 2 против зависимостей компонентов


135

plus()Метод Dagger 1 я часто использовал в предыдущих приложениях, поэтому я понимаю ситуации, когда вам может понадобиться субкомпонент с полным доступом к привязкам родительских графов.

В какой ситуации было бы полезно использовать компонентную зависимость вместо субкомпонентной зависимости и почему?

Ответы:


228

Зависимости компонентов - используйте этот параметр, если хотите сохранить независимость двух компонентов.

Субкомпоненты - используйте это, если вы хотите соединить два компонента.


Я буду использовать приведенный ниже пример для объяснения зависимостей компонентов и подкомпонентов . Вот некоторые моменты, на которые стоит обратить внимание:

  • SomeClassA1может быть создан без какой-либо зависимости. ModuleAпредоставляет и экземпляр SomeClassA1через provideSomeClassA1()метод.
  • SomeClassB1не может быть создан без SomeClassA1. ModuleBможет предоставить экземпляр, SomeClassB1только если экземпляр SomeClassA1передается в качестве аргумента provideSomeClassB1()метода.
@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 позаботится о передаче экземпляра SomeClassA1в качестве аргумента provideSomeClassB1()методу при ModuleBкаждой ModuleBинициализации объявления компонента / субкомпонента . Нам нужно проинструктировать Кинжал, как выполнить зависимость. Это можно сделать с помощью зависимости компонента или субкомпонента .

Компонентная зависимость

Обратите внимание на следующие моменты в приведенном ниже примере зависимости компонента:

  • ComponentBдолжен определить зависимость через dependenciesметод @Componentаннотации.
  • ComponentAне нужно объявлять ModuleB. Это сохраняет эти два компонента независимыми.
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();
    }
}

субкомпонент

Обратите внимание на следующие моменты в примере SubComponent:

  • Поскольку ComponentBне определила зависимость от ModuleAнее, она не может жить самостоятельно. Это становится зависимым от компонента, который обеспечит ModuleA. Следовательно, у него есть @Subcomponentаннотация.
  • ComponentAобъявил ModuleBчерез метод интерфейса componentB(). Это объединяет два компонента. На самом деле, ComponentBможет быть инициализирован только через 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);
    }
}

4
У меня есть подкомпонентная установка, которая не добавляет Модуль B в ComponentA, что означает, что компоновщик componentA не нуждается в moduleB. Похоже, это работает так, как я ожидал, разрешив создание ComponentA при запуске приложения, а затем создать экземпляр m
FriendlyMikhail

2
@MikeN - Можете ли вы выделить, как можно избавиться от ModuleB на ComponentA? Я могу избавиться от ModuleB на ComponentA, только если я предоставлю различные области действия на ComponentA и ComponentB.
Правер Гупта

1
Вы правы, мои настройки работают, потому что они находятся в разных областях. Извинения.
FriendlyMikhail

2
« SomeClassB1зависит от SomeClassA1. ComponentAдолжен явно определить зависимость.» ==> Вы имели в виду « ComponentBдолжен явно определять зависимость»?
Tar

1
Аналогично тому, на что указал @Tar, я понимаю, что в « SomeClassB1зависит от SomeClassA1. Не ComponentAнужно явно определять зависимость». Вы имели в виду « ComponentBне нужно явно определять зависимость».
Себас Л.Г.

45

Согласно документации :

Component Dependencyдает вам доступ только к привязкам, предоставляемым в качестве методов предоставления через зависимости компонентов, т.е. у вас есть доступ только к тем типам, которые объявлены в parent Component.

SubComponentдает вам доступ ко всему графу связывания от его родителя, когда он объявлен, т.е. у вас есть доступ ко всем объектам, объявленным в его Modules.

Скажем, у вас есть , ApplicationComponentсодержащее все Androidродственное вещество ( LocationService, Resources, SharedPreferenceи т.д.). Вы также хотите, чтобы DataComponentвы постоянно управляли вещами, а также имели WebServiceдело с API. Единственное, чего тебе не хватаетDataComponent это Application Contextчто находится в ApplicationComponent. Самый простой способ получить Contextот DataComponent- это зависимость ApplicationComponent. Вы должны быть уверены, что у вас есть Contextявное объявление, ApplicationComponentпотому что у вас есть доступ только к объявленным вещам. В этом случае нет ручной работы, то есть вам не нужно указывать Submodulesв parent Componentи явно добавлять свой подмодуль в родительский модуль, например:

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

Теперь рассмотрим тот случай, когда вы хотите ввести WebServiceиз DataComponentи LocationServiceиз ApplicationComponentв ваш, Fragmentкоторый связывает с помощью@Submodule plus функции выше. Крутая вещь здесь заключается в том, что компонент, к которому вы привязываете ( ApplicationComponent), не нужно раскрывать WebServiceни LocationServiceпотому, что у вас есть доступ ко всему графику сразу.


2
Если я правильно понимаю, интерфейс не называется @Submodule. Это опечатка?
Ислам Салах

Мне нравится, как это использует пример из реальной жизни, чтобы продемонстрировать разницу. Тем не менее, это более запутанно, чем чтение документов. Было бы полезно иметь меньше classesпримеров и больше картинок, чтобы проиллюстрировать точную точку зрения.
Судокодер

18

Вот пример кода со скриншотом для лучшего понимания Компонента и Подкомпонента:

Составная часть: введите описание изображения здесь

  1. AppComponent содержит две декларации.
  2. AppComponent инициализируется в классе App.
  3. HomeActivityComponent зависит от AppComponent.
  4. В HomeActivity по инициализации DaggerHomeActivityComponent я даю объект AppComponent в виде композиции.

подкомпоненте:

введите описание изображения здесь

  1. AppComponent содержит субкомпонент или субкомпоненты.
  2. AppComponent инициализируется в классе App.
  3. Субкомпонент не знает о своем ParentComponent. Это только обеспечивает свои собственные зависимости, включая модуль.
  4. В HomeActivity я внедряю субкомпонент, используя его родительский компонент.

И наглядная схема: введите описание изображения здесь

Источник: ссылка


Разве диаграмма не имела бы больше смысла, если бы подкомпонент заключал в себе AppComponent?
Флориан Вальтер,

1

Еще одна вещь, которую я до сих пор не осознавал, это то, что:

  • @SubcomponentЭкземпляр имеет ровно один родительский компонент (хотя различные компоненты могут создать экземпляр в том же @Subcomponentи быть родителем этого экземпляра)
  • A @Componentможет иметь ноль, один или несколько «родительских» компонентов, объявленных через зависимости компонентов

1
Вероятно, во втором случае неправильно говорить, что @Component может иметь ... parent (s). Скорее у @Component нет родителей, но другие могут зависеть от этого (просто используйте его) через зависимости компонентов.
Демакси

@demaksee Я не знаю, мне кажется, что если вы наметите иерархию компонентов, вы попадете в DAG, и я думаю, что это стандартный способ ссылаться на это отношение как родитель-потомок в контексте графа. Если мы говорим о внутренней работе Кинжала, то я думаю, что это не то слово.
ареколек
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.