Retrofit之OkhttpCall执行原理详解

根据《Retrofit源码解析之请求流程概述》我们知道Retrofit通过OkhttpCall来完成同步或者异步请求,那么OkhttpCall的execute和enqueue方法是什么时候开始执行的呢?这篇博文就来简单的扒一扒其内部原理。

简单以Retrofit同步请求作为说明,简单的例子如下:

interface MyApi {
  @Get
  Call getData(params)
}

MyApi mApi = retrofit.create(MyApi.class);

Call testCall= mApi.getData(params);

//*发送网络请求(同步)
Response response = testCall.execute();

//获取数据
YourBean bean = response.body();

用法很简单,就是先调用Retrofit的create方法获取一个MyApi对象,然后执行某一个getData方法返回一个Call对象,那么这个Call对象会是OkhttpCall吗?答案是No! 下面就抽丝剥茧来分析下这个Call对象是神马牛鬼蛇神。


先来看看Retrofit的create方法:

public  T create(final Class service) {
    //省略与本文无关的代码
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();

          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
             //省略无关代码

            ServiceMethod serviceMethod =
                (ServiceMethod) loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.adapt(okHttpCall);
          }
        });
  } 
  

create方法的入参是一个Interface的Class对象,但是返回的是一个Proxy.newProxyInstance代理对象,因为我们在使用Retrofit的时候只需要定义API接口及其对应的方法,而不需要自己implements API interface.但是接口的方法是用来执行的,你不实现接口怎么能执行呢?代理对象的强大之处就体现出来了:
只需要根据你传入的接口,生成一个代理对象,之后所有的方法调用都会走代理对象invoke方法;且代理对象不需要关心你具体执行方法的名字,一律以method表示. InvocationHandler接口只有一个方法,即invoke()方法!它是对代理对象所有方法的唯一实现。也就是说,无论你调用代理对象上的哪个方法,其实都是在调用InvocationHandler的invoke()方法。我们只需要invoke对Method和args进行处理即可。

可以说Retrofit就是利用代理对象的这一特性,将网络框架的使用简易化:

因为API接口所有方法调用的目的就是把方法的注解信息以及参数信息进行扫描和解析,交给OkhttpCall进行处理执行网络调用

,既然所有的API接口方法调用都是基于同一目的,那么全部就交给代理对象代劳就是了,代理的强大之处被利用的淋漓尽致。

啰嗦了这么多,下面就来看看其invoke方法都做了啥:

 //根据你调用的某个method,调用loadServiceMethod方法。获取对应的ServiceMthod对象
 ServiceMethod serviceMethod =
                (ServiceMethod) loadServiceMethod(method);
  //将参数和Service构成一个OkhttpCall对象              
  OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);

//数据返回  
return serviceMethod.adapt(okHttpCall); 
  

步骤很简单明了:
1、根据你调用某个方法method对象从缓存中获取对应的ServiceMethod对象,如果缓存没有则创建一个。
2、将method对应的serviceMethod及其参数args,初始化一个OkHttpCall对象
3、执行serviceMethod的adapt方法,返回一个Call


ServiceMthod的创建

先看看serviceMethod是怎么创建的:

ServiceMethod, ?> loadServiceMethod(Method method) {
    ServiceMethod, ?> result = serviceMethodCache.get(method);
    //缓存中有则使用缓存里面的
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        //没有缓存则创建一个ServiceMethod
        //this是Retrofit
        result = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

看看ServieMethod.Builder方法都有啥:

 Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      //获取Api某个方法的注解信息
      this.methodAnnotations = method.getAnnotations();

      //*这个解释有点绕,看https://blog.csdn.net/jiang_bing/article/details/7794365
      this.parameterTypes = method.getGenericParameterTypes();
      //获取参数的注解信息
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

从上面代码可以看出,Builder的构造器的作用就是拿到一个Method对应的信息,比如方法注解信息,参数注解信息等,然后再来看看Buider的build方法:

CallAdapter callAdapter;

public ServiceMethod build() {
      //创建一个callAdapter
      callAdapter = createCallAdapter();
      //获取方法的返回类型
      responseType = callAdapter.responseType();

      if (responseType == Response.class || responseType == okhttp3.Response.class) {
        throw methodError("'"
            + Utils.getRawType(responseType).getName()
            + "' is not a valid response body type. Did you mean ResponseBody?");
      }
      //根据returnType创建数据转换器 
      responseConverter = createResponseConverter();

      //解析方法注解
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }
      //省略部分注解处理代码:详细解析会另外开启博文说明

      return new ServiceMethod<>(this);
    }

CallAdapter方法简单说明
build方法的第一个步骤就是createCallAdapter()创建一个callAdapter,还记得上面代理对象的invoke方法最后一行吗?即return serviceMthod.adapt(OkhttpCall),内部就是调用了callAdapter的adapt方法:

 T adapt(Call call) {
    return callAdapter.adapt(call);
  }

所以继续瞅瞅createCallAdapter都干了啥:

 private CallAdapter createCallAdapter() {
      //得到目标方法返回类型对应的Type对象
      Type returnType = method.getGenericReturnType();

      //获取方法的注解信息
      Annotation[] annotations = method.getAnnotations();
      //根据热天run
        return (CallAdapter) retrofit.callAdapter(returnType, annotations);
      }
    }

至于返回哪一个CallAdapter,为了博文的条理性,在这里先直接说结论:
返回是CallAdapte是由从Anrdoid Platfom的ExecutorCallAdapterFactory工厂对象生成的

static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
      //此处的callbackExecutor就是MainThreadExecutor
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        //使用handle来post一个任务
        handler.post(r);
      }
    }
  }

ExecutorCallAdapterFactory工厂对象持有一个MainThreadExecutor ,该MainThreadExecutor的作用是将一个任务Runnable都通过handle发送到Android消息队列中去执行

进而看看这个工厂对象返回的CallAdapter是神马:

  @Override
  public CallAdapter get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    //method方法返回值类型必须是Call
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    //获取Call的泛型T的类型
    final Type responseType = Utils.getCallResponseType(returnType);

    return new CallAdapter>() {
      @Override public Type responseType() {
        //Call那么返回的就是JavaBean
        return responseType;
      }
      //最终invoke会执行的方法
      //adapt方法参数的call就是OKhttpCall
      @Override public Call adapt(Call call) {
        //callbackExecutor是MainThreadExecutor 
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  } 
  

上述get方法有几个要注意的地方:
1、Api Service定义的方法的返回值必须是Call《T》类型(当然这是没有结合rx使用的情况)
2、CallAdapter的responseType()方法返回的就是对应的JavaBean的类型,正如注释所说:For example, the response type for {@code Call} is {@code Repo}
3、最终CallAdapter的adapt返回的就是ExecutorCallbackCall,而adapt的方法参数就是我们的OKhttpCall(参见文章开头对invoke方法的说明)。也即是说下面的代码中的Call就是ExecutorCallbackCall:

/*实际上返回的就是ExecutorCallbackCall*/
Call call= Api.getData();
Resonse response = call.execute();
T data = response.body();

4、ExecutorCallbackCall持有的callbackExecutor引用指向的对象就是MainThreadExecutor

 final class ExecutorCallbackCall<T> implements Call<T>{
    //MainThreadExecutor 
    final Executor callbackExecutor;
    //OKhttpCall
    final Call delegate;

    ExecutorCallbackCall(Executor callbackExecutor, Call delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }
 }

所以文章开头testCall.execute()执行的就是ExecutorCallbackCall的execute方法,而该方法又是代理给OkhttpCall的execute方法:

//同步网络请求
 public Response execute() throws IOException {
      //OkhttpCall真正执行的地方
      return delegate.execute();
    }

那么在看看其异步网络请求:

 public void enqueue(final Callback callback) {
      //同样执行的是OKhttpCall的enqueue方法
      delegate.enqueue(new Callback() {
        @Override public void onResponse(Call call, final Response response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              if (delegate.isCanceled()) {//请求取消
                callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
              } else {
                //请求成功
                callback.onResponse(ExecutorCallbackCall.this, response);
              }
            }
          });
        }

         //网络请求失败
        @Override public void onFailure(Call call, final Throwable t) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      });
    }

异步请求其实也很简单,其内部就是调用了OkhttpCall的enqueue,只不过在回调结果的时候通过MainThreadExecutor转到了UI线程中去处理了。

到此为止OkttpCall的执行讲解完毕,代码其实很绕,分析其源码的时候各种方法来回跳转,很容易混乱。比如这个OkhttpCall可以直接返回,但是层层代码各种传递才能分析出invoke返回的Call是个什么玩意。为什么本来简单的调用要搞这么复杂呢?这个问题会从代码设计的绝对另开博客详细说明。

总结下来就是:
某ApiService定义的一系烈方法中,你调用了几个个方法,就会对应创建几个ServiceMethod对象,同时也会对应创建几个OkhttpCall来执行。

最后以一个流程图来完成做结:
Retrofit之OkhttpCall执行原理详解_第1张图片

你可能感兴趣的:(Retrofit,Retrofit)