【问题标题】:Dagger 2: @Component.Builder is missing setters for required modules or components: [appi.example.com.dagger.AppModule]`Dagger 2:@Component.Builder 缺少所需模块或组件的设置器:[appi.example.com.dagger.AppModule]`
【发布时间】:2017-10-20 08:42:27
【问题描述】:

我正在配置新的 Dagger Android 模块,但出现此错误 这是我的组件:

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

但我仍然收到错误

错误:(20, 3) 错误:@Component.Builder 缺少所需模块或组件的设置器:[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);
  }
}

【问题讨论】:

  • 您是否尝试过在您的模块方法中不使用@BindsInstance
  • @DavidMedenjak 我正在关注这个tutorial 哪个模块应该有这个?应用模块?
  • 如果你看看你上面提供的代码,一个是你自己的,另一个是匕首文档的一部分。明显的区别是,you 在您的 AppModuleNetModule 构建器方法上有一个 @BindsInstance 注释。
  • 我也遇到了同样的问题

标签: java android dependency-injection dagger-2


【解决方案1】:

Kotlin 答案

检查模块的构造函数。

如果你有构造函数和应用参数,删除它。

真实用法:

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

••• 错误用法:

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

【讨论】:

    【解决方案2】:

    在我的例子中,我使用了一个对象模块,所以我不得不用 @JvmStatic 注释提供者方法

    @Module
    object GsonModule {
    
        @JvmStatic
        @Singleton
        @Provides
        fun provideGson() = Gson()
    
    }
    

    【讨论】:

    • 代码 sn-p 将有助于更好地理解答案(并获得更多支持)
    • @Module object MainActivityModule { @JvmStatic @Provides @ActivityScope fun provideZzz(activity: MainActivity): Zzz { return Zzz(activity) } }
    【解决方案3】:

    我认为这对@BindsInstance的使用和@Provides ApplicationDagger 2 Component Builder的删除提供了一个更清晰的解释:

    @BindsInstance什么?

    这是定义:

    标记组件构建器或子组件构建器上的方法 允许实例绑定到 零件。 —— 来源

    什么?我也看不懂?

    以下是何时使用它的简单提示:

    @BindsInstance 方法应该优先于编写@Module 构造函数参数并立即提供这些值。 —— 来源

    我来自 Spring Boot,而 Dagger 2 是 OMG 复杂得多。 :(

    因此,根据我对 Dagger 2 极其有限的经验,发生这种情况是因为 *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)
    }
    

    然后在从Application 子类构造DaggerAppComponent 时提供模块的依赖关系(确保您使用specify the subclass name in 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-v4 Fragment 与原生 Fragment 的使用可能是问题的根源。例如对于support-v4,你需要使用AndroidSupportInjectionModuleHasSupportFragmentInjector,而对于native,你需要使用AndroidInjectionModuleHasFragmentInjector

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

      • 感谢您的回答,想知道为什么会这样吗?
      • Component.Builder 是 AppComponent 的自定义构建器。您为应用程序提供 BindsInstance。这就是 AppModule 知道在没有提供 Singleton 的情况下获取应用程序的方式。您使用自定义构建器,因此您不需要通过 AppModule 构造函数传递对象。
      • 那是超级答案和@LEO 精湛的解释谢谢,但是现在我们如何才能获得应用程序实例。
      • 获取任何提供的对象的方式相同
      • 我很困惑,错误说我们需要添加一个setter,但你实际上删除了一个“provides”。在我看来,这不会解决问题,而是引入另一个问题,即不能 @Inject Application 因为 AppModule 不再是 @Provides Application 。但是你说这行得通,你能澄清你的答案来解释它是如何工作的(非直觉地)吗?谢谢。
      猜你喜欢
      • 2020-09-02
      • 1970-01-01
      • 1970-01-01
      • 2020-07-01
      • 1970-01-01
      • 2018-02-22
      • 2018-01-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多