Retrofit原理解析

一、定义

Retrofit是一个网络请求封装框架,默认使用OkHttp进行网络请求,只是简化了用户的网络请求参数的封装。

二、使用

1.创建Retrofit实例

2.定义网络请求接口,并为接口中的方法添加相应的注解

3.通过动态代理生成网络请求对象

4.通过网络请求适配器将网络请求对象进行平台适配

5.通过网络清执行器,发送网络请求

6.通过数据解析器解析数据

7.通过回调执行器,切换线程

8.用户在主线程处理返回数据

网络接口

public interface WanAndroidService {
    @GET("wxarticle/chapters/json")
    Call<WxArticleBean> wxarticle();
}

使用

// 1.通过构造器模式,创建Retrofit对象
retrofit = new Retrofit.Builder()
       .baseUrl("https://wanandroid.com/")
        .addConverterFactory(GsonConverterFactory.create())
       .build();
//2.通过create的动态代理实现接口对象       
WanAndroidService service = retrofit.create(WanAndroidService.class);
//3.调用接口方法,返回Call对象
Call<WxArticleBean> listCall = service.wxarticle();
//4.通过Call对象,异步请求网络,并使用Callback接收返回数据
listCall.enqueue(new Callback<WxArticleBean>() {
    @Override
    public void onResponse(Call<WxArticleBean> call, Response<WxArticleBean> response) {
        Log.e(TAG,"thread:"+Thread.currentThread());
    }

    @Override
    public void onFailure(Call<WxArticleBean> call, Throwable t) {
        Log.e(TAG,"Throwable:"+t.getMessage());
    }
});

 上面就是一次网络请求的简单过程,使用起来确实很方便吧。只需要在接口中通过注解将需要的请求参数输入,而不需要关心怎么拼接请求参数,也不需要关心怎么处理返回数据及线程的切换。

三、原理

在看原理之前,我们需要带着几个问题来看①retrofit为什么不需要接口实现类的②它怎样将参数拼接起来的③返回的参数是怎么解析的④线程的切换是怎么做的。这样看源码时才不会陷入到源码中不可自拔。

1.通过构造器模式,创建Retrofit对象

先看Retrofit的Builder做了什么

public Builder() {
  this(Platform.get());
}

 这里只是拿到了了使用的平台类型,进入到里面看看

private static final Platform PLATFORM = findPlatform();

static Platform get() {
  return PLATFORM;
}

private static Platform findPlatform() {
  try {
    Class.forName("android.os.Build");
    if (Build.VERSION.SDK_INT != 0) {//判断是否有android sdk
      return new Android();//返回android平台
    }
  } catch (ClassNotFoundException ignored) {
  }
 ......
  return new Platform();
}

 判断是否有android sdk,有就创建Android

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

  @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
    if (callbackExecutor == null) throw new AssertionError();
    return new ExecutorCallAdapterFactory(callbackExecutor);
  }

  static class MainThreadExecutor implements Executor {
   //getMainLooper获得的Looper是主线程的,所以创建的handler是主线程的
   private final Handler handler = new Handler(Looper.getMainLooper());

    @Override public void execute(Runnable r) {
      handler.post(r);
    }
  }
}

 只是重写了父类的defaultCallbackExecutor()和defaultCallAdapterFactory(),但是看到比较熟悉的代码Handler handler = new Handler(Looper.getMainLooper()),这是比较典型的切换到主线程的方式。这里先猜测是使用handle切换线程

回到Retrofit构造器模式中,this(Platform.get())跳到的位置其实没啥

Builder(Platform platform) {
  this.platform = platform;
  // Add the built-in converter factory first. This prevents overriding its behavior but also
  // ensures correct behavior when using converters that consume all types.
  converterFactories.add(new BuiltInConverters());
}

 链式调用只是将需要的配置放入,最终创建Retrofit看build()方法

public Retrofit build() {
  if (baseUrl == null) {//如果baseUrl为空,直接报错
    throw new IllegalStateException("Base URL required.");
  }

  okhttp3.Call.Factory callFactory = this.callFactory;
  if (callFactory == null) {//如果没有设置callFactory
    callFactory = new OkHttpClient();//创建一个OkHttpClient
  }

  Executor callbackExecutor = this.callbackExecutor;
  if (callbackExecutor == null) {//如果没有设置callbackExecutor
      //还记得之前获得的Android吗?这里返回的MainThreadExecutor
    callbackExecutor = platform.defaultCallbackExecutor();
  }

  // Make a defensive copy of the adapters and add the default Call adapter.
  List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
  //将Android的ExecutorCallAdapterFactory添加到adapterFactories中
  adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

  // Make a defensive copy of the converters.
  List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

  return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
      callbackExecutor, validateEagerly);
}

build方法就是把之前设置过的值,以及没有设置,但是必须的值给赋值好,传入Retrofit构造方法来创建Retrofit对象。这里要记得callbackExecutor 是MainThreadExecutor,CallAdapter.Factory是ExecutorCallAdapterFactory,它们都是通过platform对象获得的。

2.将接口转为对象

public <T> T create(final Class<T> service) {
    //判断传入的类是否是接口以及接口中的方法是否大于0
  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, @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);
          }
          if (platform.isDefaultMethod(method)) {//默认是false
            return platform.invokeDefaultMethod(method, service, proxy, args);
          }
          //将接口方法中的参数报错在ServiceMethod中
          ServiceMethod<Object, Object> serviceMethod =
              (ServiceMethod<Object, Object>) loadServiceMethod(method);
          OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
          return serviceMethod.callAdapter.adapt(okHttpCall);
        }
      });
}

3.调用接口中的方法,返回Call对象

在调用接口的方法时,其实走的是动态代理的invoke()方法,①先将接口方法中的参数及注解解析之后存放在ServiceMethod对象中,②创建一个OkHttpCall对象,③通过CallAdapter的adapter方法将OkHttpCall转接成一个Call对象。

①先将接口方法中的参数及注解解析之后存放在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
      result = new ServiceMethod.Builder<>(this, method).build();
      serviceMethodCache.put(method, result);
    }
  }
  return result;
}

看看ServiceMethod的构造器模式

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();//获得callAdapter对象
  responseType = callAdapter.responseType();
......
  responseConverter = createResponseConverter();//获得数据解析器

  for (Annotation annotation : methodAnnotations) {
    parseMethodAnnotation(annotation);//解析方法上的注解
  }
......

  int parameterCount = parameterAnnotationsArray.length;
  parameterHandlers = new ParameterHandler<?>[parameterCount];
  for (int p = 0; p < parameterCount; p++) {
    Type parameterType = parameterTypes[p];
  ......  
    Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
   ......
    //解析方法里的入参
    parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
  }
......
    //创建ServiceMethod对象
  return new ServiceMethod<>(this);
}

build()中主要做的是:获得callAdapter对象、获得数据解析器、解析方法上的注解、解析方法里的入参这几个操作

private CallAdapter<T, R> createCallAdapter() {
  Type returnType = method.getGenericReturnType();
  ......
  Annotation[] annotations = method.getAnnotations();
  try {
    //noinspection unchecked
    return (CallAdapter<T, R>) 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);
  }
}

通过retrofit拿到CallAdapter,这个方法是在Retrofit中

public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
  return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?, ?> nextCallAdapter(@Nullable 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;
    }
  }
  ......
}

skipPast是null,还记得Retrofit构造时,只添加了ExecutorCallAdapterFactory进去了,所以indexOf返回的是-1,start是0,遍历数组,找到returnType, annotations相匹配的对象,所以最终拿到的还是ExecutorCallAdapterFactory。

private Converter<ResponseBody, T> createResponseConverter() {
  Annotation[] annotations = method.getAnnotations();
  try {
    return retrofit.responseBodyConverter(responseType, annotations);
  } catch (RuntimeException e) { // Wide exception range because factories are user code.
    throw methodError(e, "Unable to create converter for %s", responseType);
  }
}

createResponseConverter方法同样是通过方式,从Retrofit的converterFactories中的相匹配的数据解析器。

parseMethodAnnotation方法是将方法上的注解解析,判断注解的类型,然后封装请求方式,

private void parseMethodAnnotation(Annotation annotation) {
    if (annotation instanceof DELETE) {
      parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
    } else if (annotation instanceof GET) {
      parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
    }
    ......
}

parseParameter是使用入参和入参的注解来生成对应的入参对象

private ParameterHandler<?> parseParameter(
    int p, Type parameterType, Annotation[] annotations) {
  ParameterHandler<?> result = null;
  for (Annotation annotation : annotations) {
    ParameterHandler<?> annotationAction = parseParameterAnnotation(
        p, parameterType, annotations, annotation);
......
    result = annotationAction;
  }
......
  return result;
}

返回ParameterHandler对象,可以看到它的子类有Header、Path、Query等对应的注解类名。最终将这些信息放入到ServiceMethod对象中。

②创建一个OkHttpCall对象

创建OkHttpCall对象没有什么,就是将ServiceMethod和入参传入

OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
  this.serviceMethod = serviceMethod;
  this.args = args;
}

③通过CallAdapter的adapter方法将OkHttpCall转接成一个Call对象。

serviceMethod.callAdapter.adapt(okHttpCall)

从ServiceMethod中获得CallAdapter,我们保存的CallAdapter是ExecutorCallAdapterFactory,所以这里调用adapter方法是ExecutorCallAdapterFactory中的CallAdapter的adapter方法

public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
        return null;
    } else {
        final Type responseType = Utils.getCallResponseType(returnType);
        return new CallAdapter<Object, Call<?>>() {
            public Type responseType() {
                return responseType;
            }
            //serviceMethod.callAdapter.adapt最终调的是这个方法
            public Call<Object> adapt(Call<Object> call) {
                //callbackExecutor是MainThreadExecutor
                //call是OkHttpCall
                return new ExecutorCallAdapterFactory.ExecutorCallbackCall(ExecutorCallAdapterFactory.this.callbackExecutor, call);
            }
        };
    }
}

里面是创建了一个静态内部类ExecutorCallbackCall,将callbackExecutor和OkHttpCall传入进去。

static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;

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

这里其实是一个委派模式,OkHttpCall最终回调操作是交给这个类来完成的。

4.通过Call对象,异步请求网络,并使用Callback接收返回数据

拿到OkHttpCall对象之后,就是执行enqueue方法了。

public void enqueue(final Callback<T> callback) {
  checkNotNull(callback, "callback == null");

  okhttp3.Call call;
  Throwable failure;

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

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

 因为底层使用了OkHttp做网络请求,所以在调用enqueue,需要创建OkHttp的Call对象.

private okhttp3.Call createRawCall() throws IOException {
  Request request = serviceMethod.toRequest(args);
  okhttp3.Call call = serviceMethod.callFactory.newCall(request);
  if (call == null) {
    throw new NullPointerException("Call.Factory returned null.");
  }
  return call;
}

这里就是从ServiceMethod中获取到接口的方法参数封装成OkHttp的Request,同时创建一个okhttp的call对象,通过call的enqueue方法进行实际的网络请求。

还记得之前的委派模式,在OkHttpCall做enqueue时,也会调用到ExecutorCallbackCall的enqueue方法

public void enqueue(final Callback<T> callback) {
    Utils.checkNotNull(callback, "callback == null");
    this.delegate.enqueue(new Callback<T>() {
        public void onResponse(Call<T> call, final Response<T> response) {
            ExecutorCallbackCall.this.callbackExecutor.execute(new Runnable() {
                public void run() {
                    if (ExecutorCallbackCall.this.delegate.isCanceled()) {
                        callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                    } else {
                        callback.onResponse(ExecutorCallbackCall.this, response);
                    }

                }
            });
        }

        public void onFailure(Call<T> call, final Throwable t) {
            ExecutorCallbackCall.this.callbackExecutor.execute(new Runnable() {
                public void run() {
                    callback.onFailure(ExecutorCallbackCall.this, t);
                }
            });
        }
    });
}

在回调onResponse和onFailure时,会通过CallbackExecutor的execute方法,将线程切换到主线程中,这样就不需要开发者自己去切换线程了。

解析返回数据是在parseResponse方法中

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

  int code = rawResponse.code();
  if (code < 200 || code >= 300) {
    try {
      // Buffer the entire body to avoid future I/O.
      ResponseBody bufferedBody = Utils.buffer(rawBody);
      return Response.error(bufferedBody, rawResponse);
    } finally {
      rawBody.close();
    }
  }

  if (code == 204 || code == 205) {//这里是代表成功但返回数据为空时,直接返回
    rawBody.close();
    return Response.success(null, rawResponse);
  }

  ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
  try {
    T body = serviceMethod.toResponse(catchingBody);
    return Response.success(body, rawResponse);
  } catch (RuntimeException e) {
   ......
  }
}

 这一步是将OkHttp的Response的数据取出,重新封装到自己的Response中去。通过ServiceMethod的toResponse将body的数据转换为所需要的bean对象

R toResponse(ResponseBody body) throws IOException {
  return responseConverter.convert(body);
}

 这个responseConverter就是通过GsonConverterFactory生成的,具体是在ServiceMethod构造模式中。

至此,retrofit的原理就解析完了,上面的几个问题应该也有了答案。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值