Субкомпоненты 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.