OkHttp学习系列之Retrofit

Retrofit严格意义上不是OkHttp的,但是这两个东西联系太紧密了,在Android开发时,经常会把Retrofit和OkHttp混到一起用,很方便!! 所以不得不讲一下Retrofit
注意下,这篇文章是讲原理的,不是讲用法的,想学习Retrofit怎么用,不要看这篇文章,纯属浪费时间

深入到Retrofit的源码中可以看到,Retrofit的设计是非常精巧的,他利用了动态代理注解技术,用几个类搭建了一个可扩展性非常好的框架,实在是我辈的楷模。

Retrofit的逻辑分成以下三个部分

  1. 创建代理对象
  2. 对注解的解析,得到ServiceMethod,从名字上就可以看出,这是一个类的方法
  3. 对第一步解析出的ServiceMethod的调用(invoke)

除了上面两部分外,我们还会讲一下ConverterFactory

创建代理对象

直接上代码吧。
使用Retorfit要第一步当然是通过调用create方法来创建Retrofit实例

public <T> T create(final Class<T> service) {
    
    
  Utils.validateServiceInterface(service);
  if (validateEagerly) {
    
    
    eagerlyValidateMethods(service);
  }
  //核心就是这个动态代理方法,通过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 {
    
    
          ...
          //上面有一些代码,无关主流程,不看了,关键在这里,
          //先通过loadServiceMethod,解析注解,得到ServiceMethod对象
          //然后调用invoke发起实际的网络请求
          return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
        }
      });
}

解析注解(loadServiceMethod)

我们首先看loadServiceMethod方法的直接实现

ServiceMethod<?> loadServiceMethod(Method method) {
    
    
  //看到没,这里有一个cache,也就是说注解实际上只解析一次,之后就放到缓存中
  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中看看怎么解析注解的
经过简单的代码走读,我们会走到HttpServiceMethod中,这个是ServiceMethod的子类

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
    Retrofit retrofit, Method method, RequestFactory requestFactory) {
    
    
  Annotation[] annotations = method.getAnnotations();
  Type adapterType;
  if (isKotlinSuspendFunction) {
    
    
   //这里有一些Kotlin相关的代码,我们先忽略不看,我们针对的环境是Retrofit+RxJava2
   ...
  } else {
    
    
   //这里获取我们的返回值类型
    adapterType = method.getGenericReturnType();
  }

  CallAdapter<ResponseT, ReturnT> callAdapter =
  //这里实际上行是一个非常精巧的设计,我们的Retrofit支持自定义类来处理请求的,这里就是实际上会调用到我们的
 // 创建Retrofit时设置的CallAdapterFactory里面。
      createCallAdapter(retrofit, method, adapterType, annotations);
  Type responseType = callAdapter.responseType();
  
  //同上,Response的数据类型是支持自定义的,具体的解析方法在我们创建Retrofit时设置的ConverterFactory里面
  Converter<ResponseBody, ResponseT> responseConverter =
      createResponseConverter(retrofit, method, responseType);

  okhttp3.Call.Factory callFactory = retrofit.callFactory;
  if (!isKotlinSuspendFunction) {
    
    
 //到这里,我们创建了CallAdapted,就算结束了,我们拿到了CallAdapted类,注意这个名字,
 //这个类实际上是HttpServiceMethod的一个子类
    return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
  } 
}

发起网络请求

看第一章就知道,关键在invoke方法

@Override final @Nullable ReturnT invoke(Object[] args) {
    
    
 //这里是不是很熟悉,我们拿到了OkHttpCall,这个实际上是最终发起网络请求的位置
  Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
  return adapt(call, args);
}
protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);

经过简单的代码走读,我们就会发现他实际上走到了CallAdapter的adapt方法,我们找一下哪里实现了他
最终我们找到了在RxJava2CallAdapter里面,这里已经是我们在创建Retrofit时,设置的CallAdapterFactory的地盘了
继续看

//这里的Call就是我们上一段代码的OkHttpCall。
//也就是说,我们传入的CallAdapterFactory实际上就是控制我们怎么调用OkHttpCalld的问题
 @Override public Object adapt(Call<R> call) {
    
    
 //一个同步,一个异步,我们直接看同步的吧
    Observable<Response<R>> responseObservable = isAsync
        ? new CallEnqueueObservable<>(call)
        : new CallExecuteObservable<>(call);
        ...
  }
//当RxJava被observe的时候,会走到这里,这里用CallCallback封装了下
 @Override protected void subscribeActual(Observer<? super Response<T>> observer) {
    
    
    // Since Call is a one-shot type, clone it for each new observer.
    Call<T> call = originalCall.clone();
    CallCallback<T> callback = new CallCallback<>(call, observer);
    observer.onSubscribe(callback);
    if (!callback.isDisposed()) {
    
    
    //这里开始发起真正的网络请求
      call.enqueue(callback);
    }
    
 private static final class CallCallback<T> implements Disposable, Callback<T> {
    
    
    private final Call<?> call;
    private final Observer<? super Response<T>> observer;
    private volatile boolean disposed;
    boolean terminated = false;

    CallCallback(Call<?> call, Observer<? super Response<T>> observer) {
    
    
      this.call = call;
      this.observer = observer;
    }
	//拿到真实的网络请求结果
    @Override public void onResponse(Call<T> call, Response<T> response) {
    
    
      if (disposed) return;

      try {
    
    
      //看到没,看到没,我们熟悉的onNext
        observer.onNext(response);
        ...
      }
    }

ConverterFactory

使用Retrofit是可以自定义返回值类型的,
但是很奇怪,我们直接从OkHttp中拿到的肯定是string,对吧?
所以我们需要有一个地方来讲string处理成我们需要的类型。
这个地方就是OkHttpCall

//将string转为我们需要的类型
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    
    
   ResponseBody rawBody = rawResponse.body();

   // Remove the body's source (the only stateful object) so we can pass the response along.
   rawResponse = rawResponse.newBuilder()
       .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
       .build();
       ...

   ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
   try {
    
    
   ...这里就是我们进行转换的地方
     T body = responseConverter.convert(catchingBody);
     return Response.success(body, rawResponse);
   } catch (RuntimeException e) {
    
    
     // If the underlying source threw an exception, propagate that rather than indicating it was
     // a runtime exception.
     catchingBody.throwIfCaught();
     throw e;
   }
 }

猜你喜欢

转载自blog.csdn.net/weixin_43662090/article/details/115217410