Retrofit interface 支持以下几种写法

/**
 * 天气查询
 * <https://wiki.viomi.net/pages/viewpage.action?pageId=211622019>
 */
interface IHttp {

    @POST("api/app/weather/info/query")
    suspend fun queryWeather(@Body request: QueryWeatherRequest): ResponseWrapper<QueryWeatherResponse>

    @POST("api/app/weather/info/query")
    fun queryWeatherCall(@Body request: QueryWeatherRequest): Call<ResponseWrapper<QueryWeatherResponse>>

    @POST("api/app/weather/info/query")
    fun queryWeatherSingle(@Body request: QueryWeatherRequest): Single<ResponseWrapper<QueryWeatherResponse>>

    @POST("api/app/weather/info/query")
    fun queryWeatherFuture(@Body request: QueryWeatherRequest): CompletableFuture<ResponseWrapper<QueryWeatherResponse>>

    /**
     * 错误写法,会抛出异常:
     * java.lang.IllegalArgumentException: Unable to create call adapter for com.viomi.baseaction.network.ResponseWrapper<com.viomi.baseaction.weather.QueryDataResponse>
     *     for method IHttp.queryData
     * Caused by: java.lang.IllegalArgumentException: Could not locate call adapter for com.viomi.baseaction.network.ResponseWrapper<com.viomi.baseaction.weather.QueryDataResponse>.
     *     Tried:
     *         retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
     *         retrofit2.CompletableFutureCallAdapterFactory
     *         retrofit2.DefaultCallAdapterFactory
     */
    @POST("api/app/weather/info/query")
    fun queryWeatherError(@Body request: QueryWeatherRequest): ResponseWrapper<QueryWeatherResponse>
}

interface function 返回值类型是由 CallAdapter 提供的,Retrofit 内置两种类型:

class Platform {
  List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
      @Nullable Executor callbackExecutor) {
    DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
    return hasJava8Types
        ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
        : singletonList(executorFactory);
  }
}

如果添加了 RxJava Adapter api "com.squareup.retrofit2:adapter-rxjava2:${retrofitVersion}” 还可以支持 Observable、Single、Maybe、Completable 等类型

final class RxJava2CallAdapter<R> implements CallAdapter<R, Object> {
  @Override
  public Object adapt(Call<R> call) {
    Observable<Response<R>> responseObservable =
        isAsync ? new CallEnqueueObservable<>(call) : new CallExecuteObservable<>(call);

    Observable<?> observable;
    if (isResult) {
      observable = new ResultObservable<>(responseObservable);
    } else if (isBody) {
      observable = new BodyObservable<>(responseObservable);
    } else {
      observable = responseObservable;
    }

    if (scheduler != null) {
      observable = observable.subscribeOn(scheduler);
    }

    if (isFlowable) {
      return observable.toFlowable(BackpressureStrategy.LATEST);
    }
    if (isSingle) {
      return observable.singleOrError();
    }
    if (isMaybe) {
      return observable.singleElement();
    }
    if (isCompletable) {
      return observable.ignoreElements();
    }
    return RxJavaPlugins.onAssembly(observable);
  }
}

对于 suspend function,Kotlin 编译器会在参数列表尾部添加一个 Continuation ,Retrofit 以此作为特征可以判断出当前方法是否为 suspend function,如果是则用 suspendCancellableCoroutine 进入协程的世界

suspend fun queryWeather(@Body request: QueryWeatherRequest): ResponseWrapper<QueryWeatherResponse>

// 反编译后的 java 代码
Object queryWeather(@Body QueryWeatherRequest queryWeatherRequest, Continuation<? super ResponseWrapper<QueryWeatherResponse>> continuation);

对 retrofit function 参数列表进行逐个处理,在此过程中可以判断出是否为 suspend function

final class RequestFactory {
  static final class Builder {

    private @Nullable ParameterHandler<?> parseParameter(
        int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
      ParameterHandler<?> result = null;
      if (annotations != null) {
        for (Annotation annotation : annotations) {  // 处理标注在参数的 @Body、@Query 等注解
          ParameterHandler<?> annotationAction =
              parseParameterAnnotation(p, parameterType, annotations, annotation);

          if (annotationAction == null) {
            continue;
          }

          if (result != null) {
            throw parameterError(
                method, p, "Multiple Retrofit annotations found, only one allowed.");
          }

          result = annotationAction;
        }
      }

      if (result == null) {       // 如果参数没有注解、且是参数列表里的最后一位、且是 Continuation 类型
        if (allowContinuation) {  // 那么说明此参数是由 Kotlin 编译器加上的,这个方法是 suspend function
          try {
            if (Utils.getRawType(parameterType) == Continuation.class) {
              isKotlinSuspendFunction = true;
              return null;
            }
          } catch (NoClassDefFoundError ignored) {
          }
        }
        throw parameterError(method, p, "No Retrofit annotation found.");
      }

      return result;
    }
  }
}

普通函数取返回值的类型(Call、Observable...)去查找 CallAdapter,而 suspend function 它的返回值是 Response or Body 类型,找不到对应的 CallAdapter,直接使用 DefaultCallAdapterFactory,也即对于 suspend funcation 来说它是用内置的 CallAdapter

然后通过 suspendCancellableCoroutine 挂起协程,在 retrofit2.Call#enqueue 回调里恢复协程,返回响应(Continuation.resume)或者抛出异常(Continuation.resumeWithException

abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
  static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
    boolean continuationWantsResponse = false;
    boolean continuationBodyNullable = false;

    Annotation[] annotations = method.getAnnotations();
    Type adapterType;
    if (isKotlinSuspendFunction) {
      Type[] parameterTypes = method.getGenericParameterTypes();
      Type responseType =
          Utils.getParameterLowerBound(
              0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
      if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
        // Unwrap the actual body type from Response<T>.
        responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
        continuationWantsResponse = true;
      } else {
        // TODO figure out if type is nullable or not
        // Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
        // Find the entry for method
        // Determine if return type is nullable or not
      }

      adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
      annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
    } else {
      adapterType = method.getGenericReturnType();
    }

    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    Type responseType = callAdapter.responseType();
    if (responseType == okhttp3.Response.class) {
      throw methodError(
          method,
          "'"
              + getRawType(responseType).getName()
              + "' is not a valid response body type. Did you mean ResponseBody?");
    }
    if (responseType == Response.class) {
      throw methodError(method, "Response must include generic type (e.g., Response<String>)");
    }
    // TODO support Unit for Kotlin?
    if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
      throw methodError(method, "HEAD method must use Void as response type.");
    }

    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    if (!isKotlinSuspendFunction) {
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else if (continuationWantsResponse) {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>)
          new SuspendForResponse<>(
              requestFactory,
              callFactory,
              responseConverter,
              (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
    } else {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>)
          new SuspendForBody<>(
              requestFactory,
              callFactory,
              responseConverter,
              (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
              continuationBodyNullable);
    }
  }
}

static final class SuspendForBody<ResponseT> extends HttpServiceMethod<ResponseT, Object> {
  @Override
  protected Object adapt(Call<ResponseT> call, Object[] args) {
    call = callAdapter.adapt(call);
    Continuation<ResponseT> continuation = (Continuation<ResponseT>) args[args.length - 1];
    try {
      return isNullable
          ? KotlinExtensions.awaitNullable(call, continuation)
          : KotlinExtensions.await(call, continuation);
    } catch (Exception e) {
      return KotlinExtensions.suspendAndThrow(e, continuation);
    }
  }
}

suspend fun <T : Any> Call<T>.await(): T {
  return suspendCancellableCoroutine { continuation ->
    continuation.invokeOnCancellation {
      cancel()
    }
    enqueue(object : Callback<T> {
      override fun onResponse(call: Call<T>, response: Response<T>) {
        if (response.isSuccessful) {
          val body = response.body()
          if (body == null) {
            val invocation = call.request().tag(Invocation::class.java)!!
            val method = invocation.method()
            val e = KotlinNullPointerException("Response from " +
                method.declaringClass.name +
                '.' +
                method.name +
                " was null but response body type was declared as non-null")
            continuation.resumeWithException(e)
          } else {
            continuation.resume(body)
          }
        } else {
          continuation.resumeWithException(HttpException(response))
        }
      }

      override fun onFailure(call: Call<T>, t: Throwable) {
        continuation.resumeWithException(t)
      }
    })
  }
}