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.
如果我使用MutableList,那么它可以工作。因此问题是:Dagger2 / Kotlin中的List有什么问题?
答案 0 :(得分:3)
原来这是一个泛型互操作问题。
当您使用List
接口(如Interceptor
)作为Kotlin中的参数时,您会从Java的角度将其视为具有列表类型参数的通配符,因为List
是协变的:
OkHttpClient provideClient(List<? extends Interceptor> interceptors) { ... }
但是,不会为返回类型添加此通配符。
List<Interceptor> provideInterceptors() { ... }
您可以通过在Java文件中创建模块实例并查看自动完成提供的方法来检查这一点。
问题是,Dagger正在寻找List<? extends Interceptor>
,而您的其他方法正在返回List<Interceptor>
。
可能的解决方案:
使用@JvmSuppressWildCards
注释来阻止添加通配符(请参阅相关问题here)。这可以在几乎任何范围内使用,从整个模块到只有您遇到问题的单一类型参数:
interceptors: List<@JvmSuppressWildcards Interceptor>?
在您out
方法中返回的List
上添加明确的provideInterceptors
差异。有趣的是,当您从Java查看自动完成时,这并没有显示,但它修复了构建。
fun provideInterceptors(): List<out Interceptor>? { ... }
使用MutableList
界面,正如您所发现的那样,没有此问题。
至于为什么只有当您使用List
而不是MutableList
时才会发生这种情况:List
只有out
位置的类型参数,因此,它是协变的。这会导致为List
生成通配符,但不会为不变MutableList
生成通配符(这就是为什么工作正常)。
另请注意,此通配符生成仅在type参数为非final类型(开放类或接口)时发生。所以你不会得到这个问题,比如一个List<StringBuilder>
(这是最终的),但是你会得到它
List<BufferedReader>
(不是)。