How Retrofit Handles Kotlin suspend Functions
This article explains how Retrofit 2.6.0 adds support for Kotlin suspend functions by detecting the Continuation parameter, determining the return type, and generating appropriate CallAdapter implementations such as SuspendForResponse and SuspendForBody to integrate coroutine handling with OkHttp.
Retrofit 2.6.0 introduced native support for Kotlin suspend functions, allowing developers to write concise coroutine‑based network calls. The library identifies a suspend method by checking whether the last parameter is of type kotlin.coroutines.Continuation and extracts the generic type of that continuation to determine the method’s actual return type.
Quick start example shows that adding the suspend keyword to a Retrofit service method is enough:
@GET("users/{id}")
suspend fun user(@Path("id") id: Long): UserUnder the hood, a non‑suspend method compiles to a simple static method, while a suspend method compiles to a static method that receives a Continuation parameter. The decompiled bytecode reveals the extra continuation argument.
Detecting suspend methods is performed in RequestFactory. During request factory construction, the last parameter is examined; if its raw type is Continuation, the flag isKotlinSuspendFunction is set to true. This flag drives later processing.
Determining the return type involves reading the generic type of the continuation’s parameter. If the type is Response<T>, Retrofit treats the method as returning a full HTTP response; otherwise it treats it as returning the body type T. The library then creates a synthetic CallAdapter whose adapterType is a Call<T>.
Handling a Response return uses the SuspendForResponse class, which adapts the underlying OkHttpCall and invokes KotlinExtensions.awaitResponse to resume the continuation with a Response<T> object.
static final class SuspendForResponse<ResponseT> extends HttpServiceMethod<ResponseT, Object> {
private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter;
@Override
protected Object adapt(Call<ResponseT> call, Object[] args) {
call = callAdapter.adapt(call);
Continuation<Response<ResponseT>> continuation =
(Continuation<Response<ResponseT>>) args[args.length - 1];
return KotlinExtensions.awaitResponse(call, continuation);
}
}Handling a plain body return uses SuspendForBody. It adapts the call, extracts the continuation, and calls either KotlinExtensions.await or KotlinExtensions.awaitNullable depending on nullability.
static final class SuspendForBody<ResponseT> extends HttpServiceMethod<ResponseT, Object> {
private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter;
private final boolean isNullable;
@Override
protected Object adapt(Call<ResponseT> call, Object[] args) {
call = callAdapter.adapt(call);
Continuation<ResponseT> continuation =
(Continuation<ResponseT>) args[args.length - 1];
return isNullable
? KotlinExtensions.awaitNullable(call, continuation)
: KotlinExtensions.await(call, continuation);
}
}Both adapters ultimately rely on the coroutine extension functions awaitResponse and await, which enqueue the OkHttp call and resume the continuation with either the response, the body, or an exception.
In summary, Retrofit’s coroutine support adds only a few hundred lines of code but cleverly reuses existing CallAdapter infrastructure, allowing developers to write clean suspend service methods without sacrificing the flexibility of the original Retrofit API.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Sohu Tech Products
A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
