Dagger 2子组件注入错误

时间:2016-07-18 18:01:02

标签: android dependency-injection dagger-2

我有两个组件:AppComponentApiComponent。我想使用AppComponentApiComponent提供的依赖关系以及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);;
    }
}

我在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

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

2 个答案:

答案 0 :(得分:2)

我也是这个案子。我相信你想要的是@Subcomponent。我相信依赖关系指令适用于你的低级模块(为了清楚起见避免使用'sub'一词)不知道(或想知道)关于在'root'模块中声明的那些依赖关系(即包含诸如活动巴士)。引用有关组件dependencies = { };

Dagger 2文档
  

组件依赖

     

虽然子组件是组成子图的最简单方法   绑定,子组件与父母紧密耦合;他们可能会   使用由其祖先组件和子组件定义的任何绑定。   作为替代方案,组件只能使用另一个组件的绑定   通过声明组件依赖关系来组件接口。当一种类型   用作组件依赖,每个提供方法就可以了   依赖关系被绑定为提供者。请注意,只有绑定暴露   因为提供方法可以通过组件依赖性获得。

我已经尝试重新编写代码来帮助,但我不能说我理解这一切所以我会告诉你我最近是如何在我的应用程序中使用这个构造。希望这会有所帮助,您可以在案例与此之间划出相似之处。

...所以

场景:我的SplashActivity向基础模块的图表提供LocalBroadcastManager依赖项和活动 Context,并使用数据库相关性由主模块提供......与您的用例非常相似。

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

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

Snippet 2 :活动的注入说明,即SplashActivityModule

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

Snippet 3 :父(或根)模块,为图表提供入口点。

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

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

希望有所帮助。让我发布你的发现,因为我正在努力解决儿童模块无法了解父母的情况......即。 a @Subcomponent

答案 1 :(得分:0)

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

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

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

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

并确保通过声明与它们提供的依赖项具有相同名称的方法(除了大写第一个字母),父组件(接口)和依赖组件中的BOTH,显式公开父组件的依赖项,像这样:

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

还要确保公开(依赖)模块在(依赖)组件中提供的依赖项,再次,曝光方法的名称应与您的依赖项名称相同,但第一个字母除外:

UserApi userApi();

还要确保在Dagger 2上查看这个非常有用且准确的article。此stackoverflow answer帮助我确定了有关声明范围和管理依赖项生命周期的问题。

PS: 我避免使用术语“子组件”,因为在Dagger 2中声明“子组件”有不同的方法,即使从属组件和子组件在概念上是相同的。