Retrofit2实现源码分析

来源:互联网 发布:程序员团队名称大全 编辑:程序博客网 时间:2024/06/04 15:54

最近研究Retrofit2+RxJava实现网络请求及数据集处理,一部分的知识点就在Retrofit2,为了更好的理解代码,本人决定分析下Retrofit2源码,既然是分析源码就得带着目的去分析,那么说说本文要解决的问题吧,先看代码来说明

Retrofit retrofit = new Retrofit.Builder()        .client(new OkHttpClient())        .baseUrl(API_URL)        .addCallAdapterFactory(RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io()))        .addConverterFactory(GsonConverterFactory.create())        .build();ZhuanLanApi api = retrofit.create(ZhuanLanApi.class);Call<ZhuanLanAuthor> call = api.getAuthor("qinchao");call.enqueue(new Callback<ZhuanLanAuthor>() {    @Override    public void onResponse(Call<ZhuanLanAuthor> call, Response<ZhuanLanAuthor> response) {        System.out.println(response.body().getName());    }    @Override    public void onFailure(Call<ZhuanLanAuthor> call, Throwable t) {    }});

以上代码就是单独使用Retrofit2的基本方式,在写该代码时,我有几个疑惑,先列举吧。

疑惑1call.enqueue是怎么发起网络请求的,和Okhttp3发起的网络请求为什么这么相似疑惑2: 创建retrofit对象时client函数传的OkHttpClient对象有何作用疑惑3:  addCallAdapterFactory函数传参有起到什么作用疑惑4: addConverterFactory函数传参起到什么作用

下面就来解决这些疑惑

1、Retrofit2和OkHttp3的关系

实际上Retrofit2是用来解决Okhttp3用法复杂的问题的,先看看用OkHttp3实现一个异步网络请求的代码

String url = "https://www.baidu.com/";OkHttpClient okHttpClient = new OkHttpClient();MediaType JSON = MediaType.parse("application/json;charset=utf-8");RequestBody body = RequestBody.create(JSON, "{'name':'yjing','age':'12'}");Request request = new Request.Builder()        .post(body)        .url(url)        .build();Call call = okHttpClient.newCall(request);call.enqueue(new Callback() {    @Override    public void onFailure(Call call, IOException e) {        e.printStackTrace();    }    @Override    public void onResponse(Call call, Response response) throws IOException {        System.out.println("我是异步线程,线程Id为:" + Thread.currentThread().getId());    }});

注意,这里只是举个例子,传的参数是没有意义的,从代码可以看出OkHttp3使用太复杂,每次调用都得配置手动配置参数,而Retrofit2就是对OkHttp3进行了封装,使得能够通过调用一个Java方法来发起网络请求,网络请求实际上还是由OkHttp3完成的,Retrofit2只是将Java方法反射成为对应的网络请求。

由OkHttp3的使用代码可知,使用OkHttp3发起网路请求使通过Call对象来完成的,而创建Call实例对象,需要OkHttpClient对象和Request对象(这里需要注意)。

2、Retrofit2框架结构说明

在对Retrofit2源码进行解析之前,先说说其框架结构

这里写图片描述

这里的接口和类并不多

Converter:负责转换网络请求返回数据为对应格式数据的接口,其中GsonConverterFactory共厂类生产的GsonRequestBodyConverter类就是该接口的实现CallAdapter:负者决定retrofit.create()返回参数的接口,DefaultCallAdapterFactory以及RxJavaCallAdapterFactory连个工厂类生产的类都是该接口的实现ServiceMethod:这个类比较核心,几乎保存了一个API请求所有需要的数据,OkHttpCall需要从ServiceMethod中获得一个Request对象,然后得到Response后,还需要传入ServiceMethod用对应的Converter对象转将Response数据换成数据格式Retrofit:生成Retrofit对象,并初始化上面的几个接口实现类或ServiceMethod类对象

3、Retrofit类介绍

上面有代码说明Retrofit对象的初始化操作,这里为了方便说明再贴一次

Retrofit retrofit = new Retrofit.Builder()        .client(new OkHttpClient())        .baseUrl(API_URL)        .addCallAdapterFactory(RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io()))        .addConverterFactory(GsonConverterFactory.create())        .build();ZhuanLanApi api = retrofit.create(ZhuanLanApi.class);

通过build的一系列方法,完成了在Retrofit对象中实例化Convertor对应工厂类、CallAdapter对应工厂类以及OkHttpClient对象的初始化。

然后调用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);        }      });}

这里的create方法中使用了动态代理,作用是当调用对应service方法时,会执行到动态代理代码中来,并且传入service对应方法反射对象以及方法参数。而动态代理方法核心是最后三行代码,其中loadServiceMethod方法会实例化一个ServiceMethod对象,并实例化ServiceMethod对象中的一下几个关键变量

下面先在三小节说说ServiceMethod方法的关键点

3、ServiceMethod类的关键点

ServiceMethod中有callAdapter变量、responseConverter变量、toRequest方法、toResponse方法这几个关键点。

callAdapter变量

根据是否有调用addCallAdapterFactory方法来实例化,例如如果调用了addCallAdapterFactory(RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io()))则根据该工厂类创建SimpleCallAdapter(这里只是列举了该工厂类能生产的其中一种)对象

 static final class SimpleCallAdapter implements CallAdapter<Observable<?>> {    private final Type responseType;    private final Scheduler scheduler;    SimpleCallAdapter(Type responseType, Scheduler scheduler) {      this.responseType = responseType;      this.scheduler = scheduler;    }    @Override public Type responseType() {      return responseType;    }    @Override public <R> Observable<R> adapt(Call<R> call) {      Observable<R> observable = Observable.create(new CallOnSubscribe<>(call)) //          .lift(OperatorMapResponseToBodyOrError.<R>instance());      if (scheduler != null) {        return observable.subscribeOn(scheduler);      }      return observable;    }  }

如果没有调用addCallAdapterFactory方法则使用一下默认工厂类生成的CallAdapter对象。

final class DefaultCallAdapterFactory extends CallAdapter.Factory {  static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory();  @Override  public CallAdapter<?> 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 call;      }    };  }}

这里一定熬注意两种CallAdapter对象的adapt方法的差异,不同的CallAdapterFactory生产的CallAdapter类,其adapt方法的返回参数不一样,DefaultCallAdapterFactory 对应的返回参数是Call,而SimpleCallAdapter 对应的返回参数是Observable。

responseConverter变量

该变量负责根据对应规则对Response数据进行格式转化,在Retrofit类的nextResponseBodyConverter方法中可以看到,当有调用addConverterFactory(GsonConverterFactory.create())使用GsonConverterFactory或其它的工厂类生产的转换器,从代码中可以看出当添加多个工厂类时,使用第一个工厂类生产的转换器。

for (int i = start, count = converterFactories.size(); i < count; i++) {  Converter<ResponseBody, ?> converter =      converterFactories.get(i).responseBodyConverter(type, annotations, this);  if (converter != null) {    //noinspection unchecked    return (Converter<ResponseBody, T>) converter;  }}

然后我们来看看GsonConverterFactory工厂类生产的对象

final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {  private final Gson gson;  private final TypeAdapter<T> adapter;  GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {    this.gson = gson;    this.adapter = adapter;  }  @Override public T convert(ResponseBody value) throws IOException {    JsonReader jsonReader = gson.newJsonReader(value.charStream());    try {      return adapter.read(jsonReader);    } finally {      value.close();    }  }}

GsonResponseBodyConverter的convert方法会将ResponseBody 值转化为对应Java方法的返回参数T类型,如下面的方法则转化为ZhuanLanAuthor类型(解决疑惑4)。

Call<ZhuanLanAuthor> getAuthor(@Path("user") String user);

toResponse

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

这个方法将body数据转化为对应参数数据。

toRequest

/** Builds an HTTP request from method arguments. */Request toRequest(Object... args) throws IOException {  RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,      contentType, hasBody, isFormEncoded, isMultipart);  @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.  ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;  int argumentCount = args != null ? args.length : 0;  if (argumentCount != handlers.length) {    throw new IllegalArgumentException("Argument count (" + argumentCount        + ") doesn't match expected count (" + handlers.length + ")");  }  for (int p = 0; p < argumentCount; p++) {    handlers[p].apply(requestBuilder, args[p]);  }  return requestBuilder.build();}

这个方法,提供OkHttp3发起的网络请求需要的Request对象。

4、再谈Retrofit类的create方法

大致介绍完Retrofit类和ServiceMethod后,接着看Retrofit的create方法,前面说了其最后三行是关键代码

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

其中第一行代码讲了,是实例化ServiceMehod对象,第二行是实例化OkHttpCall对象,该OkHttpCall是Call接口的实现,最后调用了callAdapter.adapt方法。前面备注了要注意的就是这个adapt方法,不同的CallAdapter其对应的adapter方法不一样,如前面所说DefaultCallAdapterFactory 工厂类生产的CallAdapter adapt方法对应的返回参数是Call,而SimpleCallAdapter 对应adapt方法的返回参数是Observable,这就为之后RxJava结合Retrofit2使用留下了铺垫(解决疑惑3)。

我们看到当不添加.addCallAdapterFactory(RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io()))方法时,默认的CallAdater adapt方法直接来什么参数返回什么,也就是返回OKHttpCall对象。

到这里应该知道在本文最开始在addCallAdapterFactory之后还使用了

 Call<ZhuanLanAuthor> call = api.getAuthor("qinchao");

这种方式来返回Call在运行时,肯定是会报错的,应为实际上api.getAuthor方法返回的是Observable变量,这地方只是为了方便后面讲解,才那么写的。

5、call.enqueue发起网络请求

这里的call.enqueue放弃网络请求的时候,实际上是OKHttpCall对象发起的网络请求,看起enqueue的部分代码

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

其中createRawCall中通过获取ServiceMethod对象toRequest方法生成call对象,儿toRequest方法实际上就是获取的我们传入的.client(new OkHttpClient()) OkHttpClient对象(解决疑惑1、疑惑2)。

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

然后通过call对象调用call.enqueue方法发起网络请求,并执行回调。

到这里对Retrofit2的源码分析就算完成了,在分析的过程中也算是解决了文章开始提出的四个疑问。

6、参考文献

1、Retrofit2 源码解析http://www.jianshu.com/p/c1a3a881a1442、OkHttp3的基本用法http://www.jianshu.com/p/1873287eed87

7、Demo地址

Android Demo:https://github.com/Yoryky/AndroidDemo.git
原创粉丝点击