java.lang.IllegalArgumentException: невозможно создать адаптер вызова для kotlinx.coroutines.Deferred. - PullRequest
5 голосов
/ 06 июня 2019

У меня есть проект с сопрограммами 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 client изменил эти строки:

        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.

Ответы [ 2 ]

3 голосов
/ 06 июня 2019

Чтение https://github.com/square/retrofit/blob/master/CHANGELOG.md#version-260-2019-06-05 Я видел:

Новое: Поддержка модификатора приостановки на функции для Kotlin!Это позволяет выразить асинхронность HTTP-запросов идиоматическим образом для языка.

@ GET ("users / {id}") приостановить интерес пользователя (длинный идентификатор @Path ("id")):Пользователь

За кулисами это ведет себя так, как если бы он был определен как забавный пользователь (...): Вызов, а затем вызов с Call.enqueue.Вы также можете вернуть Response для доступа к метаданным ответа.

В настоящее время эта интеграция поддерживает только ненулевые типы тел ответа.Следуйте проблеме 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)
1 голос
/ 02 июля 2019

В моем случае я пропустил CoroutineCallAdapterFactory в моей инициализации Retrofit. Дооснащение 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()
...