Retrofit 支持suspend函数源码分析

浩浩 等级 965 1 0

Retrofit 2.6.0 之后支持接口suspend函数配合协程使用,举个例子:

ApiService

interface LoginApiService : BaseService {
    @GET("/wxarticle/chapters/json")
    suspend fun getChapters(): BaseResponse<List<Chapters>>
}

Repository

class LoginRepository : BaseRepository() {
    suspend fun getChapters(): BaseResponse<List<Chapters>> {
        val service = retrofit.create(LoginApiService::class.java)
        return withContext(Dispatchers.IO) {
            service.getChapters()
        }
    }
}

从API调用入手Retrofit.create()


  public <T> T create(final Class<T> service) {
    validateServiceInterface(service);
    return (T)
        Proxy.newProxyInstance(
            service.getClassLoader(),
            new Class<?>[] {service},
            new InvocationHandler() {
              private final Platform platform = Platform.get();
              private final Object[] emptyArgs = new Object[0];

              @Override
              public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
                  throws Throwable {
                // If the method is a method from Object then defer to normal invocation.
                if (method.getDeclaringClass() == Object.class) {
                  return method.invoke(this, args);
                }
                args = args != null ? args : emptyArgs;
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }
            });
  }

动态代理,拦截接口方法,实际调用Retrofit.loadServiceMethod()


  ServiceMethod<?> loadServiceMethod(Method method) {
    ServiceMethod<?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

ServiceMethod.parseAnnotations()

static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

    Type returnType = method.getGenericReturnType();
    if (Utils.hasUnresolvableType(returnType)) {
      throw methodError(
          method,
          "Method return type must not include a type variable or wildcard: %s",
          returnType);
    }
    if (returnType == void.class) {
      throw methodError(method, "Service methods cannot return void.");
    }

    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

RequestFactory.parseAnnotations()

  static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
    return new Builder(retrofit, method).build();
  }
new Builder(retrofit, method).build()

RequestFactory build() {
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }
      ......
      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
        parameterHandlers[p] =
            parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
      }
      ......
      return new RequestFactory(this);
    }

build()中遍历解析注解,parseParameter()中判断是否为挂起函数。

RequestFactory.parseParameter()

  ......
if (Utils.getRawType(parameterType) == Continuation.class) {
    isKotlinSuspendFunction = true;
    return null;
 }
  ......

回看ServiceMethod.parseAnnotations()返回值HttpServiceMethod.parseAnnotations()

    boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
    boolean continuationWantsResponse = false;

    if (isKotlinSuspendFunction) {
      if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
        responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
        continuationWantsResponse = true;
      }
    }

    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);
    }

这里走else if

return (HttpServiceMethod<ResponseT, ReturnT>)
          new SuspendForResponse<>(
              requestFactory,
              callFactory,
              responseConverter,
              (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter)

retrofit.loadServiceMethod()最终返回SuspendForResponse

  static final class SuspendForBody<ResponseT> extends HttpServiceMethod<ResponseT, Object> {
    private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter;
    private final boolean isNullable;

    SuspendForBody(
        RequestFactory requestFactory,
        okhttp3.Call.Factory callFactory,
        Converter<ResponseBody, ResponseT> responseConverter,
        CallAdapter<ResponseT, Call<ResponseT>> callAdapter,
        boolean isNullable) {
      super(requestFactory, callFactory, responseConverter);
      this.callAdapter = callAdapter;
      this.isNullable = isNullable;
    }

    @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);
      }
    }
  }

回看loadServiceMethod().invoke()->ServiceMethod抽象方法

abstract @Nullable T invoke(Object[] args)

子类HttpServiceMethod.invoke()

  @Override
  final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }

  protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);

调用到抽象方法adapt(),loadServiceMethod()方法返回值SuspendForResponse继承HttpServiceMethod重写了该方法

    @Override
    protected Object adapt(Call<ResponseT> call, Object[] args) {
      call = callAdapter.adapt(call);

      //noinspection unchecked Checked by reflection inside RequestFactory.
      Continuation<Response<ResponseT>> continuation =
          (Continuation<Response<ResponseT>>) args[args.length - 1];

      // See SuspendForBody for explanation about this try/catch.
      try {
        return KotlinExtensions.awaitResponse(call, continuation);
      } catch (Exception e) {
        return KotlinExtensions.suspendAndThrow(e, continuation);
      }
    }

KotlinExtensions.awaitResponse()

suspend fun <T> Call<T>.awaitResponse(): Response<T> {
  return suspendCancellableCoroutine { continuation ->
    continuation.invokeOnCancellation {
      cancel()
    }
    enqueue(object : Callback<T> {
      override fun onResponse(call: Call<T>, response: Response<T>) {
        continuation.resume(response)
      }

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

call.enqueue()内部调用continuation.resume(response)将返回值传给挂起函数,流程结束。

收藏
评论区

相关推荐

Retrofit 支持suspend函数源码分析
Retrofit 2.6.0 之后支持接口suspend函数配合协程使用,举个例子: ApiService java interface LoginApiService : BaseService { @GET("/wxarticle/chapters/json") suspend fun getChapters(): BaseResp
Retrofit 动态修改BaseUrl 操作
开发中会遇到URL需要动态切换,若你还是通过gradle打包切换是否不太灵活,下面将介绍一下retrofit基于OKhttp中动态修改URL; 原理添加拦截器,在retrofit中的现实更加灵活了如下代码: language private RetrofitUrlManager() { if (DEPENDENCY_OKHTT
死磕Java泛型(一篇就够)
Java泛型,算是一个比较容易产生误解的知识点,因为Java的泛型基于擦除实现,在使用Java泛型时,往往会受到泛型实现机制的限制,如果不能深入全面的掌握泛型知识,就不能较好的驾驭使用泛型,同时在阅读开源项目时也会处处碰壁,这一篇就带大家全面深入的死磕Java泛型。 泛型擦除初探相信泛型大家都使用过,所以一些基础的知识点就不废话了,以免显得啰嗦。
Retrofit封装Okhttp逻辑原理
总结自retrofit封装了Okhttp 本身并不能进行网络请求。只能在Android使用的网络请求框架。1.png2.pngrequest:统一完成(post/get/...) 回调陷阱:完成上一步网络请求才能进行下一步网络请求。3.pngRetrofit简化了网络请求。优化了网络请求的使用。4.png5.png7.pngbuild设计模式:参数》5个;
Java并发系列7
如果要让线程阻塞,我们在讲线程基础的时候已经分析过了。如果要让线程暂停呢,不是blocked,而是waiting,这时候有什么办法? Thread类有一个弃用的方法suspend()是线程暂停的意思,他被弃用的原因是线程挂起的时候并不会释放持有的锁资源,而且suspend()挂起的线程状态依然是runnable,这也是不合理的。 那么有没有一种简单的
java 使用远程调用模式 配置记录
Java程序打包并放在远端运行,运行添加命令,address\=8000,8000为监听端口。 dk1.7版本之前的命令 java \-agentlib:jdwp\=transport\=dt\_socket,address\=8000,server\=y,suspend\=y \-jar xxx.jar 1.7版本之后的命令 1) java \-a
java常见的 http 请求库比较
java常见的http请求库有httpclient,RestTemplate,OKhttp,更高层次封装的 feign、retrofit ##1、HttpClient HttpClient:代码复杂,还得操心资源回收等。代码很复杂,冗余代码多,不建议直接使用。 ##2、RestTemplate RestTemplate: 是 Spring 提供的用于访问
Ubuntu长时间待机Wifi无法连接
### Ubuntu长时间待机Wifi无法连接 * 重启网络 sudo service network-manager restart * 修改配置文件 > 在/etc/default/acpi-support 里面找到 # Add services to this list to stop them before susp
ubuntu 15.10 gnome 取消 挂起时锁屏
打开 dconf 系统配置编辑器 -> 搜索 suspend -> 取消勾选 ubuntu-lock-on-suspend. ![](http://static.oschina.net/uploads/space/2015/1210/230110_qcqz_237198.png) 如果要在右上角的电源菜单中显示 suspend 按钮的话,使用 firef
Android笔记之Retrofit与RxJava的组合
**依赖** implementation 'com.squareup.retrofit2:retrofit:2.5.0' implementation 'com.squareup.retrofit2:converter-gson:2.5.0' implementation 'com.squareup.retrofit2:adapt
Gradle插件Debug
设置环境变量 unix,linux       export GRADLE\_OPTS="-Xdebug -Xrunjdwp:transport=dt\_socket,address=9999,server=y,suspend=n” windows         set GRADLE\_OPTS="-Xdebug -Xrunjdwp:tra
Retrofit2的GsonConverterFactory.create()和RxJava2CallAdapterFactory.create()的实现过程以及执行过程
**一概述**   上一节分析了retrofit2从创建到执行的完整流程,本节分析一下两个非常重要的功能。数据转换器的实现以及网络请求适配器的实现。 **二、GsonConvertFactory.create()数据转换器的实现过程以及执行过程**   我们先看下GsonConvertFactory.crete()的源代码,此类在retrofit-co
Retrofit源码解析(上)
简介 Retrofit是Square公司开发的一款针对Android网络请求的框架,官网地址http://square.github.io/retrofit/ ,在官网上有这样的一句话介绍retrofit,A type-safe HTTP client for Android and Java。我们知道Retrofit底层是基于OKHttp实现的。对ok
Retrofit网络框架入门使用
1.简单介绍 ====== retrofit事实上就是对okhttp做了进一步一层封装优化。 我们仅仅须要通过简单的配置就能使用retrofit来进行网络请求了。 Retrofit能够直接返回Bean对象,比如假设我们进行一个网络接口的请求。返回来一串json字符串。那么这个时候一般我们都要拿到这个json字符串后进行解析得到相应的Bean对象,Ret
Retrofit里面Gson解析日期出错
今天解析json数据的时候出错了。 Invalid time zone indicator '6' (at offset 0) 也配置了Gson的setDateFormat格式 ,然而并没有用 最后还是加了registerTypeAdapter,这下通用了 private static final Gson gson = new GsonBuild