Dagger 2子组件注入错误

Dagger 2 sub-component injection error

我有两个组件:AppComponentApiComponent。我想在 ApiComponent 和注入 ApiComponent 的对象中使用 AppComponent 提供的依赖项。所以我将 ApiComponent 视为 AppComponent 的子组件。我已经使用 dependecies 指令将 AppComponent 声明为 ApiComponent 中的依赖项:

@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);;
    }
}

我在 IntentService1 的 onCreate() 方法中触发了注入:

@Inject SampleApi sampleApi;

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

但是我得到以下编译错误:

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

有人知道发生了什么事吗?感谢您的帮助。

我也是这个案子。我相信你在这里想要的是 @Subcomponent。我相信 dependencies 指令适用于当您的较低级别模块(为清楚起见避免使用 'sub' 一词)不知道(或想知道)在您的 'root' 模块中声明的那些依赖项(即模块与事件总线等项目)。引用有关组件 dependencies = { };

Dagger 2 文档

Component Dependencies

While subcomponents are the simplest way to compose subgraphs of bindings, subcomponents are tightly coupled with the parents; they may use any binding defined by their ancestor component and subcomponents. As an alternative, components can use bindings only from another component interface by declaring a component dependency. When a type is used as a component dependency, each provision method on the dependency is bound as a provider. Note that only the bindings exposed as provision methods are available through component dependencies.

我试过重写您的代码来提供帮助,但我不能说我完全理解,所以我将向您展示我最近是如何在我的应用程序中使用这个结构的。希望这对您有所帮助,您可以将您的案例与此进行比较。

所以....

场景:我的SplashActivity贡献了一个LocalBroadcastManager依赖和activityContext 到根模块的图形并使用主模块提供的数据库依赖项...与您的用例非常相似。

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

代码段 1:启动画面 activity 子组件

@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:activity 又名 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);
}

片段 4SplashActivity 执行注入的代码(在 onCreate 的超级调用后立即调用)

希望对您有所帮助。让我了解你的发现,因为我正在努力解决子模块无法了解父模块的情况......即不是一个@Subcomponent

我的问题是范围。我在声明范围时使用了不正确的注释。这就是我现在声明范围的方式:

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

令人恼火的是,依赖组件不能具有与其父组件相同的单例范围,并且您必须为所有单例组件声明命名范围,但原因已描述 here。另外,请确保模块中的所有提供程序方法都使用与组件范围相同的范围进行注释。这是我的提供者方法之一:

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

并确保通过在父组件(接口)和依赖项中声明与它们提供的依赖项同名的方法(首字母大写除外)来显式公开父组件的依赖项组件,像这样:

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

还要确保公开你的(依赖)模块在你的(依赖)组件中提供的依赖项,再次暴露方法的名称应该与你的依赖项的名称相同,除了第一个字母:

UserApi userApi();

还要确保检查这个非常有用和准确的 article on Dagger 2. This Whosebug 帮助我查明了我关于声明范围的问题,并管理了依赖项的生命周期。

PS: 我避免使用术语 "subcomponent",因为在 Dagger 2 中有一种不同的方法来声明 "subcomponent",即使依赖组件和子组件在概念上是相同的。