Retrofit 2.6.0 异常:java.lang.IllegalArgumentException:无法为 kotlinx.coroutines.Deferred 创建调用适配器

问题描述 投票:0回答:3

我有一个使用 Kotlin 协程和 Retrofit 的项目。

我有这些依赖性:

implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'

今天我已经将项目中的Retrofit更新为2.6.0。在 https://github.com/JakeWharton/retrofit2-kotlin-coroutines-adapter 中写道,它现在已被弃用。在 https://github.com/square/retrofit/blob/master/CHANGELOG.md#version-260-2019-06-05 中写道,Retrofit 目前支持

suspend

所以,我删除了

retrofit2-kotlin-coroutines-adapter:0.9.2
并在 Retrofit 客户端中更改了这些行:

        retrofit = Retrofit.Builder()
            .baseUrl(SERVER_URL)
            .client(okHttpClient)
            .addConverterFactory(MyGsonFactory.create(gson))
            //.addCallAdapterFactory(CoroutineCallAdapterFactory()) - removed it.
            .build()

运行时,第一个请求捕获异常:

java.lang.IllegalArgumentException: Unable to create call adapter for kotlinx.coroutines.Deferred<com.package.model.response.UserInfoResponse>
    for method Api.getUserInfo

据我了解,我可以使用

CoroutineCallAdapterFactory()
代替
CallAdapter.Factory()
,但它是抽象的。

如果在 Api 类中我更改请求,在开头添加

suspend

@FormUrlEncoded
@POST("user/info/")
suspend fun getUserInfo(@Field("token") token: String): Deferred<UserInfoResponse>

override suspend fun getUserInfo(token: String): Deferred<UserInfoResponse> =
    service.getUserInfo(token)

我得到这个例外:

java.lang.RuntimeException: Unable to invoke no-args constructor for kotlinx.coroutines.Deferred<com.package.model.response.UserInfoResponse>. Registering an InstanceCreator with Gson for this type may fix this problem.
android retrofit2 kotlin-coroutines
3个回答
35
投票

阅读https://github.com/square/retrofit/blob/master/CHANGELOG.md#version-260-2019-06-05我看到:

新功能:支持 Kotlin 函数的挂起修饰符!这可以让你 以惯用的方式表达 HTTP 请求的异步性 语言。

@GET("users/{id}") 暂停 fun user(@Path("id") long id): User

在幕后,这就像定义为 fun user(...) 一样: 调用,然后使用 Call.enqueue 调用。您还可以返回 用于访问响应元数据的响应。

目前此集成仅支持非空响应正文类型。 按照问题 3075 获取可空类型支持。

我更改了请求:添加了

suspend
并删除了
Deferred
:

@FormUrlEncoded
@POST("user/info/")
suspend fun getUserInfo(@Field("token") token: String): UserInfoResponse


override suspend fun getUserInfo(token: String): UserInfoResponse =
    service.getUserInfo(token)

然后在交互器中(或者简单地在调用方法

getUserInfo(token)
时)删除
await()

override suspend fun getUserInfo(token: String): UserInfoResponse =
    // api.getUserInfo(token).await() - was before.
    api.getUserInfo(token)

更新

有一次我在下载PDF文件时遇到了需要删除Api类中的

suspend
的情况。请参阅如何使用 Retrofit 和 Kotlin 协程下载 PDF 文件?


16
投票

就我而言,我在 Retrofit 初始化中缺少

CoroutineCallAdapterFactory
。改造v2.5.0

之前:

val retrofit = Retrofit.Builder()
                .baseUrl(BuildConfig.BASE_URL)
                .client(httpClient)
                .addConverterFactory(MoshiConverterFactory.create())
                .build()

之后:(工作代码)

val retrofit = Retrofit.Builder()
                .baseUrl(BuildConfig.BASE_URL)
                .client(httpClient)
                .addConverterFactory(MoshiConverterFactory.create())
                .addCallAdapterFactory(CoroutineCallAdapterFactory())
                .build()

0
投票

即使将

suspend
关键字添加到您的方法中,此错误也可能仍然存在。您的 Retrofit 版本可能不支持使用
suspend
函数进行调用。将您的 Retrofit 版本升级到
2.6.0
或更高版本以获得
suspend
功能支持。

© www.soinside.com 2019 - 2024. All rights reserved.