Кинжал 2: @Компонент .Builder отсутствует сеттеры для необходимых модулей или компонентов: [appi.example.com.dagger.AppModule] `

Я настраиваю новый модуль Android Dagger, но я получил эту ошибку Здесь мой компонент:

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

Ответы

Ответ 1

Удалите приведенный ниже код из AppModule.class и перестройте проект

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

Ответ 2

Я думаю, что это дает более четкое объяснение использования @BindsInstance и удаления @Provides Application, Dagger 2 Component Builder:

@BindsInstance Что?

Вот определение:

Отмечает метод в компоненте компоновщика или компоновщика подкомпонента, который позволяет экземпляру быть привязанным к какому-либо типу внутри компонента. - источник

WHAAT? Я тоже не понимаю 😛

Вот простой намек на то, когда его использовать:

Методы @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)
}

Затем вы предоставляете зависимости модулей при создании 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
    }
}

Обратите внимание, что Fragment support-v4 против использования собственного Fragment может быть источником проблем. например, для support-v4 вам нужно использовать AndroidSupportInjectionModule, HasSupportFragmentInjector, в то время как для native необходимо использовать AndroidInjectionModule, HasFragmentInjector.

Ответ 3

В моем случае я использовал объектный модуль, поэтому мне пришлось аннотировать с помощью @JvmStatic