Retrofit 基本流程分析

retrofit 是基于okhttp,使用动态代理来实现的。

动态代理

动态代理在retrofit中其实就是在运行期间去创建interface实例的。我们在使用时都会创建一个interface类,里面再添加一些接口方法。

public <T> T create(final Class<T> service) {
        return (T)
        Proxy.newProxyInstance(
            service.getClassLoader(),
            new Class<?>[] {service},
            new InvocationHandler() {
                .....
            }
}

在create方法中就实现了动态代理,通过这种防暑组建okhttp的request 和 Call 进行请求。

解析构建请求

动态代理的主要操作是在InvocationHandler#invoke中,

public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
                  throws Throwable {
                 
                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);
              }

按照正常的流程的话,方法会走到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对象,通过代理方式获取之后缓存起来下次直接取。
如果本次没获取到将会解析注解和方法。

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 这一步就是处理注解,构建RequestFactory对象,其实和在Okhttp中构建Request基本相同。

HttpServiceMethod.parseAnnotations
这步操作主要就是构建CallAdapter 和 数据转换的 Converter

在使用rxjava2的时候我们一般构建retrofit时会使用Rxjava2CallAdapterFactory这是接口方法的返回值会是Observable类型。如果不加任何calladapter的话,默认的返回类型就是Call。但是如果使用Kotlin 协程+ suspend 就可以直接写返回值类型,无需泛型表示。这是因为新版的Retrofit对suspend方法进行了处理。

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

如果时使用了suspend 并且返回参数直接写的时想要的结果,而不是Call 的话就会返回 SuspendForBody

这个和返回其他的差别还要从最初的invoke方法来看。

loadServiceMethod(method).invoke(args) ----> 

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

然后执行adapt方法。

这个抽象方法有三个实现,分别在

  • CallAdapted
  • SuspendForResponse
  • SuspendForBody

在SuspendForBody中的adapt方法中
有一个KotlinExtensions.await(call, continuation)

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

这里会直接解析除body然后根据GsonCovertFactory进行数据转换转化成实体类。

以上纯属个人分析,如有错误,还望指正

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值