【问题标题】:Dagger 2 sub-component injection errorDagger 2子组件注入错误
【发布时间】:2016-11-21 10:37:47
【问题描述】:

我有 2 个组件:AppComponentApiComponent。我想在ApiComponentApiComponent 注入的对象中使用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

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

【问题讨论】:

    标签: android dependency-injection dagger-2


    【解决方案1】:

    我也在处理这个案子。我相信你在这里想要的是@Subcomponent。我相信依赖项指令适用于当您的较低级别模块(为清楚起见避免使用“子”一词)不知道(或想知道)在您的“根”模块中声明的那些依赖项时(即具有项目的模块,例如事件总线)。引用Dagger 2关于组件dependencies = { }的文档;

    组件依赖

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

    我已尝试重写您的代码以提供帮助,但我不能说我完全理解,所以我将向您展示我最近在我的应用程序中如何使用此构造。希望这会有所帮助,您可以将您的案例与此相比较。

    所以....

    场景:我的SplashActivityLocalBroadcastManager 依赖和活动 Context 贡献给根模块的图表,并使用主模块提供的数据库依赖。 ..与您的用例非常相似。

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

    片段 1:Splash 活动子组件

    @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 4SplashActivity 进行注入的代码(在onCreate 的超级调用之后立即调用)

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

    【讨论】:

    • 刚刚解决了我的非子组件问题....我使用 Dagger 2 的次数越多,我发现的魔法就越少。它只是 java...有些是生成的,有些不是!
    【解决方案2】:

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-03-08
      • 1970-01-01
      • 2016-12-01
      • 2022-09-30
      • 2015-09-09
      • 2021-06-30
      • 1970-01-01
      相关资源
      最近更新 更多