Ошибка впрыска подкомпонента Dagger 2

android dependency-injection dagger-2

1515 просмотра

2 ответа

2689 Репутация автора

У меня есть 2 компонента: AppComponentи ApiComponent. Я хотел бы использовать зависимости, предоставленные AppComponentв ApiComponentи в объектах, в которые ApiComponentвводится. Таким образом, я вижу в ApiComponentкачестве подкомпонента AppComponent. Я объявил AppComponentкак зависимость в ApiComponentиспользовании dependeciesдирективы:

@ApiScope
@Component(dependencies = { AppComponent.class},
           modules = { ApiModule.class })
public interface ApiComponent {
    void inject(Application application);
    void inject(IntentService1 service1);

    SampleApi sampleApi();
}

Вот мой AppComponent:

@Singleton
@Component (modules = { AppModule.class })
public interface AppComponent {
    void (Class2 class2);

    Bus bus();
    SharedPreferences sharedPreferences();
    SampleApplication sampleApplication(); 
}

Соответствующая часть моего ApiModule выглядит так:

@Module
public final class ApiModule {
    @Provides
    @ApiScope
    SampleApi provideSampleApi(Retrofit retrofit) {
        return retrofit.create(SampleApi.class);;
    }
}

Я запускаю инъекцию в методе onCreate () моего IntentService1:

@Inject SampleApi sampleApi;

@Override
public void onCreate() {
    SampleApplication.get().getApiComponent().inject(this);
}

Но я получаю следующую ошибку компиляции:

SampleApi cannot be provided without an @Provides or @Produce-annotated method

Кто-нибудь знает, что происходит? Я ценю вашу помощь.

Автор: Javad Sadeqzadeh Источник Размещён: 18.07.2016 06:01

Ответы (2)


2 плюса

4676 Репутация автора

Я тоже в этом деле. Я верю, что вы хотите, чтобы здесь @Subcomponent. Я считаю, что директива зависимостей предназначена для случаев, когда ваш модуль нижнего уровня (избегая использования слова 'sub' для ясности) не знает (или не хочет знать) об этих зависимостях, объявленных в вашем корневом модуле (то есть модуле с такими элементами, как Шина событий). Цитирование документации Dagger 2 о компонентах dependencies = { };

Зависимости компонентов

В то время как подкомпоненты являются самым простым способом составить подграфы привязок, подкомпоненты тесно связаны с родителями; они могут использовать любое связывание, определенное их предком компонентом и подкомпонентами. В качестве альтернативы компоненты могут использовать привязки только из интерфейса другого компонента, объявляя зависимость компонента. Когда тип используется в качестве зависимости компонента, каждый метод обеспечения зависимости связан как поставщик. Обратите внимание, что только зависимости, предоставляемые в качестве методов предоставления, доступны через зависимости компонентов.

Я попытался переписать ваш код, чтобы помочь, но не могу сказать, что все понимаю, поэтому покажу вам, как я недавно использовал эту конструкцию в своем приложении. Надеюсь, что это поможет, и вы можете провести параллели между вашим делом и этим.

Так....

Сценарий : My SplashActivityвносит LocalBroadcastManagerзависимость и активность Context в график корневого модуля и использует зависимость от базы данных, предоставляемую основным модулем ... очень похоже на ваш вариант использования.

@PerActivity
@Subcomponent(
    modules = SplashActivityModule.class
)
public interface SplashActivityComponent {
  void inject(final SplashActivity splashActivity);
}

Фрагмент 1 : Вспомогательный компонент активности

@Module
public class SplashActivityModule {
  private final Context activity;

  /**
   * Constructs the activity module.
   *
   * @param activity The activity context.
   */
  public SplashActivityModule(final Activity activity) {
    this.activity = activity;
  }


  /**
   * Provide the (domain) context.
   *
   * @return The context of the domain module.
   */
  @Provides
  @PerActivity
  Context provideContext() {
    return activity;
  }


  /**
   * Provide the local broadcast manager.
   *
   * @return the broadcast manager.
   */
  @Provides
  @PerActivity
  LocalBroadcastManager provideLocalBroadcastManager() {
    return LocalBroadcastManager.getInstance(activity);
  }
}

Фрагмент 2 : Инструкции по инъекции для действия, известного какSplashActivityModule

@Component(modules = DomainModule.class)
public interface DomainComponent {
  SplashActivityComponent plus(final SplashActivityModule splashActivityModule);
}

Фрагмент 3 : Родительский (или корневой) модуль, обеспечивающий точку входа в граф.

@Override
protected void setupActivityComponent(final DomainComponent domainComponent) {
  domainComponent.plus(new SplashActivityModule(this)).inject(this);
}

Фрагмент 4 : SplashActivityкод, делающий инъекцию ( onCreateвызывается сразу после супер-вызова)

Надеюсь, это поможет. Держите меня в курсе ваших результатов с этим, потому что я борюсь со сценарием, при котором дочерний модуль не может знать о родителе ... то есть не a @Subcomponent.

Автор: OceanLife Размещён: 18.07.2016 10:47

0 плюса

2689 Репутация автора

Решение

Моя проблема была с областями применения. Я использовал неправильные аннотации для объявления области. Вот как я сейчас объявляю область видимости:

@Retention(RetentionPolicy.RUNTIME)
@Scope
public @interface ApiScope {
}

Досадно, что зависимый компонент не может иметь ту же область действия Singleton, что и его родительский компонент, и что вы должны объявлять именованные области для всех компонентов Singleton, но причина описана здесь . Кроме того, убедитесь, что ВСЕ методы вашего провайдера в вашем модуле имеют ту же область действия, что и область действия вашего компонента. Вот один из методов моего провайдера:

@Provides
@ApiScope
UserApi provideUserApi(Retrofit retrofit) {
    return retrofit.create(UserApi.class);
}

И убедитесь, что вы явно выставили зависимости от родительского компонента, объявив методы с тем же именем, что и предоставляемая ими зависимость (за исключением заглавных букв в первой букве), ОБА в родительском компоненте (интерфейсе) и в зависимом компоненте, например так:

Bus bus();
SharedPreferences sharedPreferences();
MyApplication myApplication();

Также убедитесь, что в вашем (зависимом) компоненте представлены зависимости, которые ваш (зависимый) модуль предоставляет, имя метода exposer также должно совпадать с именем вашей зависимости, за исключением первой буквы:

UserApi userApi();

Также обязательно ознакомьтесь с этой очень полезной и точной статьей о Dagger 2. Этот ответ о стековом потоке помог мне точно определить мою проблему с объявлением областей и управлять жизненным циклом зависимостей.

PS: я избегаю использования термина «подкомпонент», потому что в «Кинжале 2» существует другой способ объявления «подкомпонента», даже если зависимые компоненты и подкомпоненты концептуально идентичны.

Автор: Javad Sadeqzadeh Размещён: 08.08.2016 09:23
Вопросы из категории :
32x32