Dagger 2无法识别Kotlin中的provide方法。Java工作正常

gre*_*nce 3 android kotlin dagger-2

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))
    }
Run Code Online (Sandbox Code Playgroud)

错误消息如下:

AppComponent.java:15: error: java.util.List<? extends okhttp3.Interceptor> cannot be provided without an @Provides-annotated method.
Run Code Online (Sandbox Code Playgroud)

如果我使用MutableList,则可以使用。因此,问题是:Dagger2 / Kotlin中的List有什么问题?

zsm*_*b13 5

原来这是一个泛型互操作问题。

当您在Kotlin中将List接口的a(例如Interceptor)用作参数时,从Java的角度来看,您会认为它具有列表类型参数的通配符,因为它List是协变的:

OkHttpClient provideClient(List<? extends Interceptor> interceptors) { ... }
Run Code Online (Sandbox Code Playgroud)

但是,不会为返回类型添加此通配符。

List<Interceptor> provideInterceptors() { ... }
Run Code Online (Sandbox Code Playgroud)

您可以通过在Java文件中创建模块的实例,然后查看自动完成功能提供的方法来进行检查。

因此,问题在于Dagger在寻找List<? extends Interceptor>其他方法返回a的同时List<Interceptor>

可能的解决方案:

  1. 使用@JvmSuppressWildCards注释可防止添加通配符(请参阅此处的相关问题)。从整个模块到您遇到问题的单个类型参数,它几乎可以在任何范围内使用:

    interceptors: List<@JvmSuppressWildcards Interceptor>?
    
    Run Code Online (Sandbox Code Playgroud)
  2. outList您要在provideInterceptors方法中返回的上添加显式方差。有趣的是,当您从Java查看自动补全功能时,这不会显示出来,但是它可以修复构建。

    fun provideInterceptors(): List<out Interceptor>? { ... }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 使用MutableList您发现的界面没有此问题。


至于为什么只在使用a List而不是a 时发生这种情况MutableListList仅在out位置上使用其type参数,因此它是协变的。这将导致为a List而不是为不变量生成通配符MutableList(这就是为什么可以正常工作的原因)。

另请注意,仅当type参数为非最终类型(开放类或接口)时,才会发生通配符生成。因此,您不会因为一个问题List<StringBuilder>(这是最终的)而遇到这个问题,但您会因为一个问题List<BufferedReader>(不是)而得到它 。