首页 > 解决方案 > 字符串在 Dagger 中被多次绑定

问题描述

我在匕首中注入字符串时遇到问题

这是我的实现

@Singleton
@Component(
    modules = [AndroidInjectionModule::class,
        ActivityBuilder::class,
        ViewModelModule::class,
        NetModule::class,
        AppModule::class]
)
interface AppComponent : AndroidInjector<DaggerApplication> {

    fun inject(theDApplication: TFTScreenApplication)

    override fun inject(instance: DaggerApplication)

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

        @BindsInstance
        @Named(Constants.API_URL_KEY)
        fun apiUrl(apiUrl: String): Builder

        @BindsInstance
        @Named(Constants.SOCKET_URL_KEY)
        fun socketUrl(socketUrl: String): Builder

        fun build(): AppComponent
    }
}

然后在网络模块

@Module
abstract class NetModule {

    @Binds
    @Named(Constants.API_URL_KEY)
    abstract fun provideApiUrl(apiUrl: String): String

    @Binds
    @Named(Constants.SOCKET_URL_KEY)
    abstract fun provideSocketUrl(socketUrl: String): String

    @Module
    companion object {

        @Provides
        @Reusable
        @JvmStatic
        fun providesOkHttpClient(): OkHttpClient {
            return OkHttpClient.Builder()
                .build()
        }

        @Provides
        @Reusable
        @JvmStatic
        fun providesGson(): Gson {
            val gsonBuilder = GsonBuilder()
            gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
            return gsonBuilder.create()
        }

        @Provides
        @Reusable
        @JvmStatic
        fun providesRetrofit(
            @Named(Constants.API_URL_KEY) apiUrl: String, gson: Gson
        ): Retrofit {
            return Retrofit.Builder()
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create(gson))
                .baseUrl(apiUrl)
                .build()
        }

        @Provides
        @Reusable
        @JvmStatic
        fun providesBackOffStrategy(): BackoffStrategy {
            return ExponentialWithJitterBackoffStrategy(5000, 5000)
        }

        @Provides
        @Reusable
        @JvmStatic
        fun providesLifeCycle(application: Application): Lifecycle {
            return AndroidLifecycle.ofApplicationForeground(application)
        }

        @Provides
        @Reusable
        @JvmStatic
        fun providesScarlet(
            @Named(Constants.SOCKET_URL_KEY) socketUrl: String, okHttpClient: OkHttpClient,
            backoffStrategy: BackoffStrategy,
            lifecycle: Lifecycle
        ): Scarlet {
            return Scarlet.Builder()
                .webSocketFactory(okHttpClient.newWebSocketFactory(socketUrl))
                .addMessageAdapterFactory(MoshiMessageAdapter.Factory())
                .addStreamAdapterFactory(RxJava2StreamAdapterFactory())
                .backoffStrategy(backoffStrategy)
                .lifecycle(lifecycle)
                .build()
        }

        @Provides
        @Reusable
        @JvmStatic
        fun providesCoinSocket(scarlet: Scarlet): SocketService {
            return scarlet.create(SocketService::class.java)
        }

        @Provides
        @Reusable
        @JvmStatic
        fun providesPISAPIs(retrofit: Retrofit): PISAPIs {
            return retrofit.create(PISAPIs::class.java)
        }
    }

错误是

错误:[Dagger/DuplicateBindings] java.lang.String 被多次绑定:公共抽象接口 AppComponent 扩展 dagger.android.AndroidInjector { ^ @org.jetbrains.annotations.NotNull @Named("API_URL") @BindsInstance com.example。 tftscreen.common.di.component.AppComponent.Builder com.example.tftscreen.common.di.component.AppComponent.Builder.apiUrl(String) @org.jetbrains.annotations.NotNull @Named("SOCKET_URL") @BindsInstance com. example.tftscreen.common.di.component.AppComponent.Builder com.example.tftscreen.common.di.component.AppComponent.Builder.socketUrl(String) java.lang.String 在 com.example.tftscreen.common.di 注入.module.NetModule.provideSocketUrl(socketUrl) @javax.inject.Named("SOCKET_URL") java.lang。字符串在 com.example.tftscreen.common.di.module.NetModule.providesScarlet(socketUrl, ...) 处注入 com.tinder.scarlet.Scarlet 在 com.example.tftscreen.common.di.module.NetModule.providesCoinSocket( Scarlet) com.example.tftscreen.pis.SocketService 在 com.example.tftscreen.pis.data.PISRemoteRepository(socketService, ...) 处注入 com.example.tftscreen.pis.data.PISRemoteRepository 在 com.example.tftscreen 处注入。 pis.PISViewModel(pisRemoteRepository) com.example.tftscreen.pis.PISViewModel 在 com.example.tftscreen.common.di.module.ViewModelModule.bindPISViewModel(pisViewModel) 注入 java.util.Map,javax.inject.Provider> 注入在 com.example.tftscreen.common.presentationLayer。ViewModelFactory(creators) com.example.tftscreen.common.presentationLayer.ViewModelFactory 在 com.example.tftscreen.common.di.module.ViewModelModule.provideViewModelFactory(viewModelFactory) 注入 androidx.lifecycle.ViewModelProvider.Factory 在 com.example 注入。 tftscreen.pis.PISActivity.viewModelFactory com.example.tftscreen.pis.PISActivity 在 dagger.android.AndroidInjector.inject(T) [com.example.tftscreen.common.di.component.AppComponent → com.example.tftscreen. common.di.module.ActivityBuilder_BindMainActivity.PISActivitySubcomponent] 也要求在:com.example.tftscreen.common.di.module.NetModule.provideApiUrl(apiUrl)module.ViewModelModule.provideViewModelFactory(viewModelFactory) androidx.lifecycle.ViewModelProvider.Factory 在 com.example.tftscreen.pis.PISActivity.viewModelFactory 注入 com.example.tftscreen.pis.PISActivity 在 dagger.android.AndroidInjector.inject(T ) [com.example.tftscreen.common.di.component.AppComponent → com.example.tftscreen.common.di.module.ActivityBuilder_BindMainActivity.PISActivitySubcomponent] 也要求在:com.example.tftscreen.common.di.module。 NetModule.provideApiUrl(apiUrl)module.ViewModelModule.provideViewModelFactory(viewModelFactory) androidx.lifecycle.ViewModelProvider.Factory 在 com.example.tftscreen.pis.PISActivity.viewModelFactory 注入 com.example.tftscreen.pis.PISActivity 在 dagger.android.AndroidInjector.inject(T ) [com.example.tftscreen.common.di.component.AppComponent → com.example.tftscreen.common.di.module.ActivityBuilder_BindMainActivity.PISActivitySubcomponent] 也要求在:com.example.tftscreen.common.di.module。 NetModule.provideApiUrl(apiUrl)android.AndroidInjector.inject(T) [com.example.tftscreen.common.di.component.AppComponent → com.example.tftscreen.common.di.module.ActivityBuilder_BindMainActivity.PISActivitySubcomponent] 也在:com.example.tftscreen .common.di.module.NetModule.provideApiUrl(apiUrl)android.AndroidInjector.inject(T) [com.example.tftscreen.common.di.component.AppComponent → com.example.tftscreen.common.di.module.ActivityBuilder_BindMainActivity.PISActivitySubcomponent] 也在:com.example.tftscreen .common.di.module.NetModule.provideApiUrl(apiUrl)

标签: javaandroidkotlindagger-2dagger

解决方案


@BindsInstance, 当您需要在运行时将依赖项引入对象图中时,这是最有用的。

@Binds当您需要将接口绑定到实现并且dagger可以为您构造具体实现时使用(通过@Inject构造函数)

它看起来不像您的Constants.SOCKET_URL_KEY&Constants.API_URL_KEY符合这两个标准中的任何一个,所以...

如果这些确实在编译时可用并且您希望 dagger 提供这些,那么最简单的方法是将以下内容添加到您的模块中:

@Provides
@JvmStatic
@Named(Constants.API_URL_KEY)
fun providesApiUrlKey(): String {
  return "YOUR_API_KEY"      
}

并删除:

@BindsInstance
@Named(Constants.API_URL_KEY)
fun apiUrl(apiUrl: String): Builder

在任何一种情况下(在运行时或编译时可用),您都需要删除它:

@Binds
@Named(Constants.API_URL_KEY)
abstract fun provideApiUrl(apiUrl: String): String

@Binds
@Named(Constants.SOCKET_URL_KEY)
abstract fun provideSocketUrl(socketUrl: String): String

推荐阅读