Dagger 2: @Component.Builder缺少必需模块或组件的设置器:[appi.example.com.dagger.AppModule]

48

我正在配置新的Dagger Android模块,但是我遇到了这个错误。这是我的Component:

@AppScope
@Component(modules = {AppModule.class, NetModule.class})
public interface AppComponent {

  @Component.Builder
  interface Builder {
    @BindsInstance
    Builder application(ExampleApplication application);

    @BindsInstance
    Builder appModule(AppModule appModule);

    @BindsInstance
    Builder netModule(NetModule netModule);

    AppComponent build();
  }

  void inject(ExampleApplication __); 
...

这是我在我的应用程序中构建的方式

appComponent = DaggerAppComponent
      .builder()
      .application(this)
      .appModule(new AppModule(this))
      .netModule(new NetModule())
      .build()
      .inject(this);

但我仍然收到错误信息:

Error:(20, 3) error: @Component.Builder缺少必需的模块或组件的setter方法:[app.example.com.dagger.AppModule]

根据文档,这应该是正确的。我错了哪里呢?

例如,以下代码可以是带有Builder的有效组件:

@Component(modules = {BackendModule.class, FrontendModule.class})
interface MyComponent {
  MyWidget myWidget();

  @Component.Builder
  interface Builder {
    MyComponent build();
    Builder backendModule(BackendModule bm);
    Builder frontendModule(FrontendModule fm);
  }
}

2
你尝试过在你的模块方法中不使用@BindsInstance吗? - David Medenjak
@DavidMedenjak 我正在跟随这个教程,哪个模块应该有它?是应用程序模块吗? - Leonardo Deleon
2
如果您查看上面提供的代码,其中一个是您自己的,另一个是dagger文档的一部分。显而易见的区别是,您在AppModuleNetModule构建器方法上有一个@BindsInstance注释。 - David Medenjak
1
我也遇到了同样的问题。 - Saravanan
5个回答

56

从AppModule.class中删除以下代码并重新构建项目。

    @Provides
    @Singleton
    Application provideContext(SomeApplication application) {
        return application;
    }

11
谢谢您的回复,我很好奇为什么这个方法有效? - nmu
9
Component.Builder 是 AppComponent 的自定义生成器。您提供 BindsInstance 用于应用程序,这是 AppModule 知道获取应用程序的方式,而不需要 Provides Singleton。使用自定义 builder 可以避免通过 AppModule 构造函数传递对象。 - LEO
这是一个超级棒的答案,@LEO 的解释也非常好,谢谢。但现在我们该如何获取应用程序实例呢? - Tushar Pandey
获取任何提供的对象的方法都是相同的。 - LEO
2
我有点困惑,错误提示说我们需要添加一个setter,但你实际上删除了一个“提供”。在我的理解中,这不会解决问题,反而会引入另一个问题,即无法@Inject应用程序,因为AppModule不再@Provides应用程序。但你说这个方法可行,能否澄清一下你的答案,解释一下它是如何(非直观地)工作的?谢谢。 - Hendy Irawan
当我们想要提供在运行时获取的依赖项时,例如上面所述的应用程序实例在运行时过程中检索到,我们使用@.BindInstance。而在使用@.Builder时,不需要在模块内注释@.Provides来提供在运行时接收到的依赖项。 - mangkool

24

我认为这篇文章提供了一个更加清晰的解释,关于@BindsInstance的使用及删除@Provides ApplicationDagger 2 Component Builder:

@BindsInstance是什么?

以下是定义:

在组件构建器或子组件构建器上标记一个方法,允许将实例绑定到组件中的某些类型。— 来源

什么?我也不理解

以下是一个简单的提示,说明何时使用它:

应优先考虑使用@BindsInstance方法,而不是编写带有构造函数参数并立即提供这些值的@Module。— 来源

我来自Spring Boot,Dagger 2比较复杂 :(

基于我的极其有限的Dagger 2经验,这是由于存在一个具有构造函数参数的*Module配置错误。我仍然不知道如何正确配置具有构造函数参数的Module,但我宁愿按照Dagger 2文档给出的推荐方法,删除构造函数参数并改用@BindsInstance@Inject

例如:

@Module
class NetModule { // no constructor argument here!

    @Inject @Named("mqttServer") // replaced by @Inject
    internal lateinit var mqttServer: String

}

并且在AppComponent中:

@Singleton
@Component(modules = [AndroidSupportInjectionModule::class, AppModule::class, NetModule::class, ActivityBuilder::class])
interface AppComponent {

    @Component.Builder
    interface Builder {
        @BindsInstance
        fun application(application: Application): Builder

        @BindsInstance // you'll call this when setting up Dagger
        fun mqttServer(@Named("mqttServer") mqttServer: String): Builder

        fun build(): AppComponent
    }

    fun inject(app: GeoAssistantApp)
}

在构建DaggerAppComponent时,您需要提供模块的依赖项,这是从Application子类中完成的(请确保在AndroidManifest.xml指定子类名称):

class GeoAssistantApp : Application(), HasActivityInjector, HasSupportFragmentInjector {

    @Inject
    internal lateinit var activityDispatchingAndroidInjector: DispatchingAndroidInjector<Activity>
    @Inject
    internal lateinit var fragmentDispatchingAndroidInjector: DispatchingAndroidInjector<Fragment>

    override fun onCreate() {
        super.onCreate()
        Log.i(GeoAssistantApp::class.java.simpleName, "Initializing DaggerAppComponent...")
        DaggerAppComponent.builder()
                // list of modules/dependencies of modules that are part of this component need to be created here too
                .application(this)
                .mqttServer(getString(R.string.mqtt_server))
                .build()
                .inject(this)
    }

    override fun activityInjector(): AndroidInjector<Activity> {
        return activityDispatchingAndroidInjector
    }

    override fun supportFragmentInjector(): AndroidInjector<Fragment> {
        return fragmentDispatchingAndroidInjector
    }
}

请注意,support-v4Fragment和原生Fragment的使用可能会引起问题。例如,对于support-v4,您需要使用AndroidSupportInjectionModuleHasSupportFragmentInjector,而对于原生,您需要使用AndroidInjectionModuleHasFragmentInjector


18

在我的情况下,我正在使用一个模块对象,因此我必须使用@JvmStatic为提供程序方法进行注释

@Module
object GsonModule {

    @JvmStatic
    @Singleton
    @Provides
    fun provideGson() = Gson()

}

一小段代码片段会有助于更好地理解答案(并得到更多的赞)。 - Rajkiran
1
`@Module object MainActivityModule {@JvmStatic @Provides @ActivityScope fun provideZzz(activity: MainActivity): Zzz { return Zzz(activity) }}` - ror
这个对我有效! - CodeAndWave

2

Kotlin答案

检查您的模块构造函数。

如果您有构造函数和应用程序参数,请将其删除。

正确用法:

@Module
class MyModule { 
   // This is example module for true usage.
}

••• 错误用法:

@Module
class MyModule constructor(application: Application) { 
   // This is example module for wrong usage.
}

0
在我的情况下,我的模块类有一个构造函数,移除@BindInstance是解决方案。
该模块:
@Module
class SomeModule(private val count:Int)

组件构建器:

@Component.Builder
interface Builder {
    fun engineModule(someModule: SomeModule): Builder
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接