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

Dagger 2 doesn't recognize provide method in Kotlin. Java works fine

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 有什么问题?

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

当您在 Kotlin 中使用接口的 List(如 Interceptor)作为参数时,您会看到它具有来自 [=64= 的列表的类型参数的通配符]的观点,因为List是协变的:

OkHttpClient provideClient(List<? extends Interceptor> interceptors) { ... }

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

List<Interceptor> provideInterceptors() { ... }

您可以通过在 Java 文件中创建模块的实例并查看自动完成提供的方法来检查这一点。

所以问题是 Dagger 正在寻找 List<? extends Interceptor> 而你的另一个方法是 returning List<Interceptor>.

可能的解决方案:

  1. 使用@JvmSuppressWildCards annotation to prevent the wildcard from being added (see a related question )。这几乎可以在任何范围内使用,从整个模块一直到您遇到问题的单个类型参数:

    interceptors: List<@JvmSuppressWildcards Interceptor>?
    
  2. provideInterceptors 方法中 return 在 List 上添加显式 out 方差。有趣的是,当您从 Java 查看自动完成时,这并没有显示,但它修复了构建。

    fun provideInterceptors(): List<out Interceptor>? { ... }
    
  3. 使用MutableList接口,正如您所发现的那样,没有这个问题。


至于为什么只有当您使用 List 而不是 MutableList 时才会发生这种情况: List 仅在 out 位置具有其类型参数,因此,它是协变的。这会导致为 List 生成通配符,但不会为不变的 MutableList 生成通配符(这就是为什么它可以正常工作)。

另请注意,此通配符生成仅在类型参数为非最终类型(开放 class 或接口)时发生。所以你不会得到这个问题,比如 List<StringBuilder> (这是最终的),但你会得到它 List<BufferedReader>(不是)。