Retrofi2源码解析(二)

上一篇讲解了retrofit2的简单用法,这一边主要解析一下reftofit2的原理,就从Retrofit的create(final Class<T> service)方法看起,这个方法返回一个call对象,访问网路是通过这个对象去访问的。

我们先来看看create()这个方法里干了些什么:

 public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(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, 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);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            ServiceMethod serviceMethod = loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }</span>
当看到proxy是不是有点眼熟呢,没错就是动态代理,主要使用newProxyInstance()方法来返回一个类的代理实例,它的参数需要传递一个类的加载器,类本身,以及InvocationHandler的子类对象,这里它使用的是匿名内部类。主要动作都是在InvocationHandler中进行的,它里面只有一个invoke()方法,每当我们调用代理类里面的方法时,invoke()方法都会被执行,我们可以从参数中获得很多信息,method的方法名,从args中获取到方法的参数等。

invoke()方法里主要做的就是:

首先,将method转换为serviceMethod;

然后,通过serviceMethod,arg获取到okHttpCall对象;

最后,通过serviceMethod.callAdapter.adapt()对okHttpCall进行封装返回call对象。

下面一步步来分析。

一、将method转换为serviceMethod

ServiceMethod loadServiceMethod(Method method) {
    ServiceMethod result;
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = new ServiceMethod.Builder(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

这里很容易理解,就是通过ServiceMethod的构造器构造一个serviceMethod对象,并把它缓存起来。下面来看看这个构造器的build(0方法里都干了些啥:

public Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations();
      this.parameterTypes = method.getGenericParameterTypes();
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

public ServiceMethod build() {
      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?");
      }
      responseConverter = createResponseConverter();

      ...
      return new ServiceMethod<>(this);
    }
首先在builder的构造方法里初始化一些参数,然后再build()方法里通过new ServiceMethod(),并将这个对象返回来获得servicMethod对象,下面来仔细看看build()方法:

1、createCallAdapter()获得callAdapter,源码如下:

private CallAdapter<?> createCallAdapter() {
      Type returnType = method.getGenericReturnType();
      if (Utils.hasUnresolvableType(returnType)) {
        throw methodError(
            "Method return type must not include a type variable or wildcard: %s", returnType);
      }
      if (returnType == void.class) {
        throw methodError("Service methods cannot return void.");
      }
      Annotation[] annotations = method.getAnnotations();
      try {
        return retrofit.callAdapter(returnType, annotations);
      } catch (RuntimeException e) { // Wide exception range because factories are user code.
        throw methodError(e, "Unable to create call adapter for %s", returnType);
      }
    }
这个方法里最主要就是获取到method的类型和注解,然后调用了retrofit的callAdapter()方法,

public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }</span>
而retrofit的callAdapter()方法调用的是自己的nextCallAdapter()方法:

<span style="font-size:14px;">public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
    checkNotNull(returnType, "returnType == null");
    checkNotNull(annotations, "annotations == null");

    int start = adapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
      CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }

这个方法里,遍历了adapterFactories,从中获取callAdapter对象,adapterFactories这个集合中有哪些calAdapter对象呢,

public static final classBuilder {
    ...
    publicBuilderaddCallAdapterFactory(CallAdapter.Factory factory) {
      adapterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }
    ...
    public Retrofitbuild() {
      List<CallAdapter.Factory> adapterFactories = newArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
    ...
    }  
  }

CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
    if(callbackExecutor != null) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }
    return DefaultCallAdapterFactory.INSTANCE;
  }
上面的代码中我们可以看到,不管我们有没有往adapterFactories中添加元素,adapterFactories集合中都至少会有一个ExcutorCallAdapterFactory对象,也就是说上面通过createCallAdapter()方法得到的callAdapter就是ExcutorCallAdapterFactory,这个在后面很关键。

2、createResponseConverter()得到responseConverter转换器对象,它的作用是寻找合适的数据类型转换器,

这个的过程和构造callAdapter对象基本一致,这里不再赘述。

二、通过serviceMethod,arg获取到okHttpCall对象

OkHttpCall(ServiceMethod<T> serviceMethod, Object[] args) {
    this.serviceMethod = serviceMethod;
    this.args = args;
  }
这一步比较简单,就是传递参数

三、通过serviceMethod.callAdapter.adapt()对okHttpCall进行封装返回call对象

我们知道serviceMethod.callAdapter就是ExcutorCallAdapterFactory,那我们只要看ExcutorCallAdapterFactory的adapt()方法就可以了:
<R> T adapt(Call<R> call);
就这么一句,这是嘛呀,但是经过第一步的分析,我们已知道serviceMethod.callAdapter就是ExecutorCallAdapterFactory,那么我们可以看看在ExecutorCallAdapterFactory类中有没有发现CallAdapter的另类应用呢,一看,果不其然在重写父类的get()方法中我们找到了答案:
@Override
  public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Call<?>>() {
      @Override public Type responseType() {return responseType;
      }

      @Override public <R> Call<R> adapt(Call<R> call) {return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

当看到return new CallAdapter中的adapt(Call call)我们就完全知其所以然了,至于ExecutorCallbackCall怎么应用的我们在发起网络请求的时候讲解。

ok,当我们得到接口的代理实例之后,通过代理接口调用里面的方法,就会触发InvocationHandler对象中的invoke方法,从而完成上面的三个步骤并且返回一个Call对象,通过Call对象就可以去完成我们的请求了,Retrofit为我们提供两种请求方式,一种是同步,一种是异步。我们这里就以异步方式来讲解:

当我们通过retrofit的create()方法获得call对象,再调用call.enque()去访问网络时,方法中有回掉函数,回掉函数里重写两个方法,一个成功,一个失败,来看下怎么回事,这个call对象其实就是ExcutorCallAdapterFactory,来看里面具体实现:
public static final classExecutorCallbackCall<T> implementsCall<T> {
    finalExecutorcallbackExecutor;
    finalCall<T> delegate;

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

    @Overridepublicvoidenqueue(final Callback<T> callback) {
      if(callback == null)thrownewNullPointerException("callback == null");

      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> 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<T> call, final Throwable t) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      });
    }

在ExecutorCallbackCall类中,封装了两个对象一个是callbackExecutor,它主要是把现在运行的线程切换到主线程中去,一个是delegate对象,这个对象就是真真正正的执行网络操作的对象,那么它的真身到底是什么呢?还记得我们在获取代理接口第三步执行的serviceMethod.callAdapter.adapt(okHttpCall)的分析吧,经过辗转几步终于把okHttpCall传递到了new ExecutorCallbackCall<>(callbackExecutor, call);中,然后看看ExecutorCallbackCall的构造方法:

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

可以知道delegate即使okHttpCall对象,来看okHttCall怎么异步访问网络的:
@Override 
public void enqueue(final Callback<T> callback) {
    if (callback == null) throw new NullPointerException("callback == null");

    okhttp3.Call call;
    Throwable failure;

    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;

      call = rawCall;
      failure = creationFailure;
      if (call == null && failure == null) {
        try {
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          failure = creationFailure = t;
        }
      }
    }

    if (failure != null) {
      callback.onFailure(this, failure);
      return;
    }

    if (canceled) {
      call.cancel();
    }

    call.enqueue(new okhttp3.Callback() {
      @Override 
      public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
          throws IOException {
        Response<T> response;
        try {
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
        callSuccess(response);
      }

      @Override 
      public void onFailure(okhttp3.Call call, IOException e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      private void callFailure(Throwable e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      private void callSuccess(Response<T> response) {
        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
    });
  }

上面的代码中可以看到,里面封装了一个okhttp3.Call对象,直接利用okhttp进行异步网络访问,okhttp怎么访问网络的这里不再讲解,感兴趣的可以自行翻看源码。
好了到这里,retrofit访问网络的原理基本解析完毕,希望能对大家有帮助,有什么不对之处还请多多指正。







  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值