Підкомпоненти 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;
    }
}

Кинджал подбає про передачу екземпляра 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();
    }
}

Підкомпонент

Зверніть увагу на наступні моменти в прикладі підкомпонента:

  • Оскільки 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, що означає, що конструктору компонентA не потрібен модульB. Це, здається, працює так, як я очікував, дозволяючи створити ComponentA при запуску програми, а потім інстанціювати m
FriendlyMikhail

2
@MikeN - Ви можете виділити, як ви могли позбутися від ModuleB на ComponentA? Я можу позбутися від ModuleB на ComponentA лише в тому випадку, якщо надаю різні сфери застосування для ComponentA та ComponentB.
Praveer Gupta

1
Ви маєте рацію, що моє налаштування працює, тому що вони є в різних сферах. вибачення.
FriendlyMikhail

2
" SomeClassB1залежить від SomeClassA1. ComponentAмає чітко визначити залежність." ==> Ви мали на увазі " ComponentBмає чітко визначити залежність"?
Тар

1
Аналогічно тому, що вказував @Tar, я розумію, що в " SomeClassB1залежить від SomeClassA1. ComponentAНе потрібно чітко визначати залежність". ви мали на увазі " ComponentBне потрібно чітко визначати залежність".
Себас LG

45

Відповідно до документації :

Component Dependencyнадає вам доступ лише до прив’язок, що піддаються методам надання через залежність від компонентів, тобто ви маєте доступ лише до тих типів, які оголошені у батьківському режимі Component.

SubComponentнадає вам доступ до всього графіку прив'язки від його батьківського під час його декларування, тобто у вас є доступ до всіх об'єктів, оголошених у його Modules.

Скажімо, у вас є , ApplicationComponentщо містить всі Androidродинне речовина ( LocationService, Resources, SharedPreferenceі т.д.). Ви також хочете мати місце, DataComponentде ви керуєте речами для наполегливості, а також WebServiceмати справу з API. Єдине, чого вам бракує, DataComponentце те, Application Contextщо проживає ApplicationComponent. Найпростіший спосіб отримати Contextвід DataComponentб залежність ApplicationComponent. Ви повинні бути впевнені, що ви Contextчітко заявили, ApplicationComponentоскільки у вас є лише доступ до заявлених матеріалів. У цьому випадку ручної роботи немає, це означає, що вам не потрібно вказувати Submodulesв батьківському режимі 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. SubComponent не знає про його ParentComponent. Це лише забезпечення власних залежностей, включаючи модуль.
  4. У програмі HomeActivity я вставляю SubComponent за допомогою свого батьківського компонента.

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

Джерело: посилання


Чи не матиме діаграма більше сенсу, якби підкомпонент додав додаток AppComponent?
Флоріан Уолтер

1

Ще одна річ, яку я ще не зовсім усвідомлював, це те, що:

  • @SubcomponentПримірник має рівно один батьківський компонент (хоча різні компоненти можуть створити екземпляр в тому ж @Subcomponentі бути батьком цього примірника)
  • А @Componentможе мати нульовий, один або багато "батьківських" компонентів, оголошених через залежність компонентів

1
Можливо, у другому випадку неправильно сказати, що "@Component" може мати ... батьків (и). Швидше у "@Component" немає батьків, але інші можуть залежати від цього (просто скористайтеся ним) через залежність від компонентів.
demaksee

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