Dagger 无法识别 Kotlin 中提供的一个方法。这是模块的重要部分:
@Provides
@AppScope
fun provideClient(cache: Cache, interceptors: List<Interceptor>?): OkHttpClient {
val httpBuilder = OkHttpClient.Builder()
interceptors?.let {
for (interceptor in interceptors) {
httpBuilder.addInterceptor(interceptor)
}
}
return httpBuilder
.cache(cache)
.build()
}
@Provides
@AppScope
fun provideInterceptors(): List<Interceptor>? {
return listOf(HttpLoggingInterceptor().setLevel(WebServiceConfig.LOGGING_LEVEL))
}
错误消息如下:
AppComponent.java:15: error: java.util.List<? extends okhttp3.Interceptor> cannot be provided without an @Provides-annotated method.
如果我使用可变列表,那么它可以工作。因此,问题是:Dagger2/Kotlin 中的列表有什么问题?
事实证明,这是一个泛型互操作问题。
当您在 Kotlin 中使用接口的List
(如Interceptor
(作为参数时,从 Java 的角度来看,您会看到它具有列表类型参数的通配符,因为List
是协变的:
OkHttpClient provideClient(List<? extends Interceptor> interceptors) { ... }
但是,不会为返回类型添加此通配符。
List<Interceptor> provideInterceptors() { ... }
您可以通过在 Java 文件中创建模块的实例并查看自动完成提供的方法来检查这一点。
所以问题是dagger正在寻找List<? extends Interceptor>
而您的其他方法正在返回List<Interceptor>
。
可能的解决方案:
使用
@JvmSuppressWildCards
注释可防止添加通配符(请参阅此处的相关问题(。这几乎可以在任何范围内使用,从整个模块一直到您遇到问题的单个类型参数:interceptors: List<@JvmSuppressWildcards Interceptor>?
在
provideInterceptors
方法中返回的List
上添加显式out
差异。有趣的是,当您查看 Java 中的自动完成功能时,这不会显示出来,但它修复了构建。fun provideInterceptors(): List<out Interceptor>? { ... }
使用
MutableList
界面,正如您发现的那样,该界面没有此问题。
至于为什么这只发生在你使用List
而不是MutableList
时:List
只在out
位置有其类型参数,因此它是协变的。这会导致为List
生成通配符,但不为不变MutableList
生成通配符(这就是正常工作的原因(。
另请注意,仅当类型参数为非最终类型(开放类或接口(时,才会生成此通配符。所以你不会得到这个问题,比如说一个List<StringBuilder>
(这是最终的(,但你会得到它List<BufferedReader>
(不是(。