Цикъл на включване на модул Dagger

Все още съм нов в Dagger и се опитвам да схвана нещата. Исках да разделя моите модули на логически групи, всяка от които предоставя собствена функционалност, но в общи линии ще действа по същия начин, както ако е в един модул.

Например, да кажем, че имам основния си приложен модул, дефиниран както следва:

//com.example.android.MyAppModule.java
@Module(
   includes = AnalyticsModule.class,
   injects = { <snip> }
)
public class MyAppModule {
   // various provides
}

И имам друг модул, дефиниран по този начин, който настройва интерфейс на ErrorReporter и предоставя конкретното им изпълнение.

// com.example.android.analytics.AnalyticsModule.java
@Module(
   addsTo = MyAppModule.class,
   injects = { MyApp.class }
)
public class AnalyticsModule(){

    // ErrorReporter is a public interface and ErrorReporterImpl is a package-local final concrete class that implements it
    @Provides @Singleton
    ErrorReporter providesErrorReporter(ErrorReporterImpl reporter) { return reporter };
}

В моя клас Application настроих обектната графика така:

// com.example.android.MyApp.java
public class MyApp extends Application {
    @Inject ErrorReporter errorReporter;

    @Override
    public void onCreate() {
        super.onCreate();
        applicationGraph = ObjectGraph
            .create(new MyAppModule())
            .plus(new AnalyticsModule());
        applicationGraph.inject(this);
        errorReporter.initialize();
    }
}

Когато стартирам компилатора на dagger, получавам нещо подобно:

Graph validation failed: Module Inclusion Cycle:
0. com.example.android.analytics.AnalyticsModule included by com.example.android.MyAppModule
1. com.example.android.modules.MyAppModule included by com.example.android.analytics.AnalyticsModule
0. com.example.android.analytics.AnalyticsModule

Какво правя грешно тук? Предполагам, че има нещо общо с include/addsTo, но когато ги премахна, получавам други грешки.

Ако премахна include = AnalyticsModule.class от MyAppModule, получавам нещо подобно:

com.example.android.analytics.ErrorReporter could not be bound with key com.example.android.analytics.ErrorReporter required by com.example.android.MyApp for com.example.android.MyAppModule

Всичко е наред, ако напълно се откажа от AnalyticsModule и след това предам providesErrorReporter на MyAppModule, но тогава трябва да направя моя конкретен impl клас публичен, за да мога да го използвам в другия модул.


person Paul    schedule 03.02.2014    source източник
comment
Възможно ли е да имате ред като includes = MyAppModule.class в анотацията на AnalyticsModule? Защото това би образувало цикъл. Освен това plus(new AnalyticsModule()) е ненужен, includes = AnalyticsModule.class ще направи това вместо вас.   -  person Tavian Barnes    schedule 05.02.2014
comment
Не, само addsTo. Захванах се за работа, ако премахнах addsTo и след това маркирах AnalyticsModule complete = false... но имам чувството, че това е така, за да мога да се прострелям в крака.   -  person Paul    schedule 05.02.2014
comment
О, добре, това има смисъл.   -  person Tavian Barnes    schedule 05.02.2014


Отговори (2)


addsTo= е там, за да укаже, че тази графика е разширение на референтния модул в родителска/дъщерна графика. .plus() е версията за изпълнение на това. Имате нужда от .plus() само ако имате екземпляри, управлявани от графи с по-кратък живот. Това съответства приблизително на понятието "обхват" в Guice и други DI контейнери.

Във вашия пример вие правите:

applicationGraph = ObjectGraph
    .create(new MyAppModule())
    .plus(new AnalyticsModule());

Това завършва със създаването на две графики във връзка родител/дете, което не е това, от което се нуждаете тук. В приложение за Android искате една графика за приложението.

Можете просто да премахнете addsTo и MyAppModule автоматично ще създаде AnalyticsModule, или можете да предадете и двете, ако искате да избегнете динамичната инициализация по следния начин:

applicationGraph = ObjectGraph.create(new MyAppModule(), new AnalyticsModule());

Цикълът на включване на модула е, защото имате циклична връзка между тези два модула и самите модули трябва да формират ациклична графика на конфигурацията. MyAppModule включва AnalyticsModule, който от своя страна включва MyAppModule. (addsTo е по-малко строго включва = използвано за указване на неща, получени от родителски графики)

person Christian Gruber    schedule 20.02.2014

@Module(includes = AnalyticsModule.class) е полезно за композиране на множество модули в един модул. В този случай използването на .plus(new AnalyticsModule()) е грешно, защото AnalyticsModule вече е включено от реда includes в анотацията. Така че трябва да премахнете обаждането до plus().

@Module(addsTo = MyAppModule.class) е за разрешаване на повикване до .plus(new AnalyticsModule()). Тъй като премахнахме това повикване, трябва да премахнем и addsTo.

@Module(complete = false) е необходимо за AnalyticsModule, защото някои от неговите зависимости не могат да бъдат задоволени сами. Това е добре; докато MyAppModule има complete = true (по подразбиране), Dagger ще извърши необходимата проверка за грешки.

Вярно е, че грешката „Цикъл на включване на модул“ беше малко неясна. Цикълът е причинен от A, включително B, което се добавя към A.

person Tavian Barnes    schedule 04.02.2014
comment
Страхотно, благодаря за обяснението. Има ли някаква документация за различните входове към анотацията @Module? Открих, че самият код е коментиран добре, но беше трудно да намеря примери/уроци за това къде бихте искали да използвате различните ключове за различни неща. - person Paul; 05.02.2014
comment
Няма много официална документация за подобни неща. Те имат някои примери в github и кратък урок на началната им страница. Бих препоръчал просто да го използвате за известно време, ще разберете. - person Tavian Barnes; 07.02.2014
comment
Тук имате addsTo назад. @Module(addsTo = MyAppModule.class) class SubModule {}` не е за разрешаване на graph.plus(new MyAppModule);, той е за разрешаване на ObjectGraph.create(new MyAppModule()) и след това graph.create(new SubModule()); Дъщерният модул се добавя към родителя в смисъл, че създадената графика е разширение, обединение на дъщерни и родителски графи. Решението обаче е правилно - изобщо не се нуждаете от addsTo в тази ситуация. - person Christian Gruber; 21.02.2014
comment
@ChristianGruber Вашият коментар ме обърка за известно време, защото мисля, че имахте предвид graph.plus(new SubModule()), а не graph.create. Но независимо от това, прав си, ще поправя отговора. - person Tavian Barnes; 24.02.2014
comment
Уф! Да - това възнамерявах. :) graph.plus(...) - person Christian Gruber; 24.02.2014