I have a project with Kotlin coroutines and Retrofit.
I had these dependencies:
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'
Today I have updated Retrofit to 2.6.0 in the project. In https://github.com/JakeWharton/retrofit2-kotlin-coroutines-adapter it is written that it is deprecated now. In https://github.com/square/retrofit/blob/master/CHANGELOG.md#version-260-2019-06-05 it is written that Retrofit currently supports suspend
.
So, I removed retrofit2-kotlin-coroutines-adapter:0.9.2
and in Retrofit client changed these lines:
retrofit = Retrofit.Builder() .baseUrl(SERVER_URL) .client(okHttpClient) .addConverterFactory(MyGsonFactory.create(gson)) //.addCallAdapterFactory(CoroutineCallAdapterFactory()) - removed it. .build()
When run, the first request catches an exception:
java.lang.IllegalArgumentException: Unable to create call adapter for kotlinx.coroutines.Deferred<com.package.model.response.UserInfoResponse> for method Api.getUserInfo
As I understood, instead of CoroutineCallAdapterFactory()
I could use CallAdapter.Factory()
, but it is abstract.
If in Api class I change a request adding suspend
in the beginning:
@FormUrlEncoded @POST("user/info/") suspend fun getUserInfo(@Field("token") token: String): Deferred<UserInfoResponse> override suspend fun getUserInfo(token: String): Deferred<UserInfoResponse> = service.getUserInfo(token)
I get this exception:
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.
Reading https://github.com/square/retrofit/blob/master/CHANGELOG.md#version-260-2019-06-05 I saw:
New: Support suspend modifier on functions for Kotlin! This allows you to express the asynchrony of HTTP requests in an idiomatic fashion for the language.
@GET("users/{id}") suspend fun user(@Path("id") long id): User
Behind the scenes this behaves as if defined as fun user(...): Call and then invoked with Call.enqueue. You can also return Response for access to the response metadata.
Currently this integration only supports non-null response body types. Follow issue 3075 for nullable type support.
I changed requests so: added suspend
and removed Deferred
:
@FormUrlEncoded @POST("user/info/") suspend fun getUserInfo(@Field("token") token: String): UserInfoResponse override suspend fun getUserInfo(token: String): UserInfoResponse = service.getUserInfo(token)
Then in interactor (or simply when called the method getUserInfo(token)
) removed await()
:
override suspend fun getUserInfo(token: String): UserInfoResponse = // api.getUserInfo(token).await() - was before. api.getUserInfo(token)
UPDATE
Once I encountered a situation when downloading PDF files required removing suspend
in Api class. See How to download PDF file with Retrofit and Kotlin coroutines?.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With