使用@ Component.Builder和构造函数参数
我试图学习匕首,kotlin和mvvm,所以如果这个问题很奇怪,请原谅我。
如果我有一个NetworkModule,基本上提供了翻新的应用程序,我认为这是一个好主意,传入基础的网址,我们要建立翻新。 我可以通过传入应用程序的组件构建函数来以旧的方式来做到这一点,但不能通过@ Component.Builder方法来解决这个问题。 尝试:
App.kt
DaggerAppComponent.builder() .application(this) .networkModule(BuildConfig.BASE_URL) .build() .inject(this)
AppComponent.kt
@Singleton @Component(modules = arrayOf( AppModule::class, NetworkModule::class, AndroidInjectionModule::class, ActivityBuilder::class)) interface AppComponent { @Component.Builder interface Builder { @BindsInstance fun application(application: Application): Builder @BindsInstance fun networkModule(baseUrl: String): Builder fun build(): AppComponent } fun inject(app: App) }
NetworkModule.kt
@Module class NetworkModule(baseUrl: String) { //Attempt to force a public setter for Dagger var baseUrl: String = baseUrl set @Provides @Singleton fun provideHttpLoggingInterceptor(): HttpLoggingInterceptor { val loggingInterceptor = HttpLoggingInterceptor { message -> Timber.d(message) } loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY return loggingInterceptor } @Provides @Singleton fun provideOkHttpClient(httpLoggingInterceptor: HttpLoggingInterceptor): OkHttpClient { val httpClientBuilder = OkHttpClient.Builder() if (BuildConfig.DEBUG) httpClientBuilder.addInterceptor(httpLoggingInterceptor) return httpClientBuilder.build() } @Provides @Singleton fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit { return Retrofit.Builder() .baseUrl(baseUrl) .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build() } }
错误是相当清楚,但我仍然不明白是什么意思:) @Component.Builder is missing setters for required modules or components: [core.sdk.di.module.NetworkModule]
。 我试图强制模块为基础网址创建一个公共setter(虽然我认为这是不需要的)。
要创建一个组件,需要提供所有的模块。 现在Dagger可以创建任何一个没有参数构造函数的模块,所以你不需要传入它。
@Module class NetworkModule(baseUrl: String) { /* ... */ }
你声明了一个在它的构造函数中有一个参数的模块,因此Dagger不能构造它。 这是错误试图告诉你的:
@ Component.Builder缺少所需模块或组件的setter:[core.sdk.di.module.NetworkModule]
你有一个模块必须手动添加(因为Dagger不能构造它),但是你的@Component.Builder
没有办法包含它。
你提供的是一个绑定的String
作为你的基础URL,这不是最好的想法,因为你可能想要在你的项目中使用多个String
对象。 你应该考虑使用一个@Qualifier
,但更多的这一点以后。
@Component.Builder interface Builder { @BindsInstance fun application(application: Application): Builder // binds a `String` to the component @BindsInstance fun networkModule(baseUrl: String): Builder // no method to set the NetworkModule! fun build(): AppComponent }
要解决你的问题,你有2个选项。 您可以创建一个setter并将url传递给模块构造函数,然后将模块设置在组件(1)上,或者可以绑定url并在模块中简单地使用它,从构造函数(2)中删除参数。
(1)自己创建模块
这是比较简单的方法,因为您只需自己创建模块并将其传递到Dagger组件构建器。 你所要做的就是将你的String的绑定替换为模块的setter。
@Component.Builder interface Builder { @BindsInstance fun application(application: Application): Builder // add the module manually fun networkModule(networkModule: NetworkModule): Builder fun build(): AppComponent }
创建组件时,您现在必须将该模块添加到构建器。
builder .application(app) .networkModule(NetworkModule(MY_BASE_URL)) // create the module yourself .build()
(2)实际绑定的网址
为了将url绑定到组件,并简单地在你的模块中使用它,就像你想要的那样,你必须从你的构造函数中删除参数。
@Module class NetworkModule() { /* ... */ } // no-arg constructor
通过这样做匕首现在可以创建模块,你将摆脱那个错误。 我们不想把这个url放在构造函数中,而是用Dagger来传递它,但是如上所述,使用String
并不是最优的,因为它实际上告诉Dagger你想要任何String
值。 您应该使用限定符来添加适当的区别,例如@Named("baseUrl") String
。
有关限定符的更多信息
@Component.Builder interface Builder { @BindsInstance fun application(application: Application): Builder // bind a `String` named "baseUrl" to this component @BindsInstance fun baseUrl(@Named("baseUrl") baseUrl: String): Builder fun build(): AppComponent }
匕首现在知道有一个@Named("baseUrl") String
,我们现在也可以在我们的模块中使用。
@Module class NetworkModule() { // other methods omitted @Provides @Singleton fun provideRetrofit( // request a String named baseUrl from Dagger @Named("baseUrl") baseUrl: String, okHttpClient: OkHttpClient ): Retrofit { return Retrofit.Builder() .baseUrl(baseUrl) // ... .build() }
就是这样。
@ Component.Builder缺少所需模块或组件的setter:[core.sdk.di.module.NetworkModule]
错误是非常直接的,构建器缺少一个方法来指定确切的NetworkModule
类型,它不知道如何构建。
@BindsInstance fun networkModule(baseUrl: String): Builder
这段代码绑定了String
类型,它对NetworkModule
的创建没有影响。 由于无法注入NetworkModule
,并且没有零参数构造函数,因此必须直接使用构建器的类型进行设置:
fun networkModule(module: NetworkModule): Builder
在App.kt
,然后使用.networkModule(NetworkModule(BuildConfig.BASE_URL))
重写构建器,它应该成功构建。