我试图学习匕首和kotlin以及mvvm,如果这个问题很奇怪,请原谅我。
如果我有一个NetworkModule,它基本上为应用程序提供了改进,我认为传递我们想要构建改造的基本URL是个好主意。我可以通过App的组件构建功能传递旧方式,但不能通过@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]
。我试图强制模块为基本网址创建公共设置器(虽然我认为不需要)。
答案 0 :(得分:19)
要创建组件,需要提供所有模块。现在,Dagger可以创建任何具有no-arg构造函数的模块,因此您不必将其传入。
@Module
class NetworkModule(baseUrl: String) { /* ... */ }
你声明一个模块在其构造函数中有一个参数,因此Dagger无法构造它。这是错误试图告诉你的:
@ Component.Builder缺少必需模块或组件的setter:[core.sdk.di.module.NetworkModule]
您有一个必须手动添加的模块(因为Dagger无法构建它),但您的@Component.Builder
无法包含它。
您提供的是String
作为基本网址的绑定,这不是最好的主意,因为您可能希望在项目中使用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)。
这是一种更简单的方法,因为您只需自己创建模块并将其传递给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()
要将url绑定到组件并在模块中使用它 - 就像你想要的那样 - 你必须从构造函数中删除参数。
@Module
class NetworkModule() { /* ... */ } // no-arg constructor
通过这样做,Dagger现在可以创建模块,您将摆脱该错误。我没有把url放在构造函数中,而是让它由Dagger传递,但如上所述使用String
并不是最佳的,因为它实际上告诉Dagger你想要那个值对于任何String
。您应该使用限定符来添加适当的区别,例如@Named("baseUrl") String
。
More information about qualifiers
@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
}
Dagger现在知道我们现在也可以在我们的模块中使用@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()
}
就是这样。
答案 1 :(得分:3)
@ Component.Builder缺少必需模块或组件的setter:[core.sdk.di.module.NetworkModule]
错误是非常字面的,构建器缺少一个方法来指定它不知道如何构建的确切类型R
。
NetworkModule
这段代码绑定了@BindsInstance
fun networkModule(baseUrl: String): Builder
类型,它对String
的创建没有影响。由于NetworkModule
无法注入且没有零参数构造函数,因此必须直接使用构建器的类型进行设置:
NetworkModule
在fun networkModule(module: NetworkModule): Builder
中,然后使用App.kt
重写构建器,它应该成功构建。