Retrofit2.0的使用及原理解析

现在Retrofit2.0的使用已经非常普遍了,我们先来了解连个问题。

1、什么是Retrofit?

Retrofit是针对Android和Java的,基于okHttp的,轻量级、安全并使用注解的方式的网络请求框架。

2、它有哪些优势

首先,Retrofit使用注解方式,大大简化了我们的URL拼写形式,而且注解含义一目了然,简单易懂;

其次,Retrofit使用简单,结构层次分明,每一步都能清晰的表达出之所以要使用的寓意;

再者,Retrofit支持同步和异步执行,使得请求变得异常简单,只要调用enqueue/execute即可完成;

最后,Retrofit更大自由度的支持我们自定义的业务逻辑,如自定义Converters。

好,知道了Retrofit是什么,有了哪些优势,现在我们来学习下怎么使用。

在学习Retrofit之前,最好先了解下OkHttpClient的使用OkHttp完全解析,因为Retrofit说到底底层还是通过OkHttp来实现的。

一、Retrofit的使用

1、在使用之前说先gradle中添加依赖:

compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'
compile 'com.squareup.okhttp:okhttp:2.5.0'
compile 'com.squareup.okhttp:okhttp-urlconnection:2.5.0'
compile files('libs/fastjson.jar')

这里我们使用的是fastjson来解析,同时也支持其他工具来解析,然后导入fastjson.jar包。


2、定义一个接口,用来存放用语网络请求的方法:

public interface HttpApi {

    @POST("/DeviceInfo-queryallinfo.php")
    Call<BaseArrayResponse<EquipModel>> getEquipInfo(@Body BaseRequest request);

}
@GET和@POST是最常用的注解,分别用来获取和发送网络请求。

3、创建Retrofit对象

public class HttpApiClient {
    private static final  String BASE_URL = "http://lbsdevicesys.duapp.com";
    private static OkHttpClient sOkHttpClient;
    private HttpApi mHttpApi;

    public HttpApiClient() {
        sOkHttpClient = new OkHttpClient();
        CookieManager cookieManager = new CookieManager();
        cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
        sOkHttpClient.setCookieHandler(cookieManager);
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .client(sOkHttpClient)
                .addConverterFactory(new FastjsonConvertFactory<>())
                .build();
        mHttpApi = retrofit.create(HttpApi.class);
    }

    private static class HttpApiClientHolder{
        private static final HttpApiClient INSTANCE = new HttpApiClient();
    }

    public static HttpApiClient getInstance() {
        return HttpApiClientHolder.INSTANCE;
    }

    public void getEquipInfo() {
        if(mHttpApi != null) {
            BaseRequest request = new BaseRequest();
            mHttpApi.getEquipInfo(request).enqueue(new retrofit.Callback<BaseArrayResponse<EquipModel>>() {
                @Override
                public void onResponse(Response<BaseArrayResponse<EquipModel>> response, Retrofit retrofit) {
                    List<EquipModel> list = response.body().getObjList();
                    Log.e("weilei", list.get(0).getManufacturer());
                }

                @Override
                public void onFailure(Throwable t) {
                    Log.e("weilei", "onFailure");
                }
            });
        }
    }
}
在这里首先创建一个Retrofit对象,通过Retrofit的构造者分别添加baseUrl、client、conveterFactory,其中baseUrl是必须的,client如果不指定默认就是一个okHttpClient,conveterFactory用于将返回的json字符串转换成我们定义的对象类型,同时将请求参数类型转换成对应的url,这里我们是这么写的,当然方式是多样的:

public class FastjsonConvertFactory<T> extends Converter.Factory{
    private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
    private static final Charset UTF_8 = Charset.forName("UTF-8");

    public FastjsonConvertFactory() {}

    @Override
    public Converter<ResponseBody, T> fromResponseBody(final Type type, Annotation[] annotations) {
        return new Converter<ResponseBody, T>() {
            @Override
            public T convert(ResponseBody value) throws IOException {
                return JSON.parseObject(value.string(), type);
            }
        };
    }

    @Override
    public Converter<T, RequestBody> toRequestBody(Type type, Annotation[] annotations) {
        return new Converter<T, RequestBody>() {
            @Override
            public RequestBody convert(T value) throws IOException {
                return  RequestBody.create(MEDIA_TYPE, JSON.toJSONString(value).getBytes(UTF_8));
            }
        };
    }

}

最后只用通过调用以下代码就可以发送网络请求了,整个使用过程非常简单、方便、灵活。

HttpApiClient.getInstance().getEquipInfo();

不过我们不能仅限于知道如何使用,还应该将进一步了解它的原理。


二、Retrofit的原理解析

从上面的例子我们可以知道,Retrofit是通过构造者模式构造的,来看一下Retrofit.Builder的build()方法的源码:

    public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      OkHttpClient client = this.client;
      if (client == null) {
        client = new OkHttpClient();
      }

      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(Platform.get().defaultCallAdapterFactory(callbackExecutor));

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

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

defaultCallAdapterFactory(callbackExecutor)的源码如下:

  CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
    if (callbackExecutor != null) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }
    return DefaultCallAdapter.FACTORY;
  }

DefaultCallAdapter的源码如下:

final class DefaultCallAdapter implements CallAdapter<Call<?>> {
  static final Factory FACTORY = new Factory() {
    @Override
    public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
      if (Utils.getRawType(returnType) != Call.class) {
        return null;
      }
      Type responseType = Utils.getCallResponseType(returnType);
      return new DefaultCallAdapter(responseType);
    }
  };

  private final Type responseType;

  DefaultCallAdapter(Type responseType) {
    this.responseType = responseType;
  }

  @Override public Type responseType() {
    return responseType;
  }

  @Override public <R> Call<R> adapt(Call<R> call) {
    return call;
  }
}

1、首先判断baseUrl是否为空,为空的话抛出一个异常;

2、然后判断client是否为空,是的话创建一个OkHttpClient对象;

3、在adapterFactories中添加一个CallAdapter.Factory对象,这个CallAdapter.Factory对象是这么来的: 

  首先我们在构造Retrofit的时候如果传入了一个Executor对象,那么就通过这个Executor对象new一个ExecutorCallAdapterFactory对象;否则就返回一个DefaultCallAdapter.FACTORY

4、最后一步构建一个List存放Converter.Factory

Retrofit构造完成后结下来会调用它的一个很重要的方法,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);
            }
            return loadMethodHandler(method).invoke(args);
          }
        });
  }
在这个方法中是一个典型的应用动态代理的方式生成一个HttpApi的代理对象,当通过代理对象调用方法的时候,会通过调用loadMethodHandler(method).invoke(args)来调用HttpApi中的方法。

下面看一下loadMethodHandler(method).invoke(args)的实现:

  MethodHandler<?> loadMethodHandler(Method method) {
    MethodHandler<?> handler;
    synchronized (methodHandlerCache) {
      handler = methodHandlerCache.get(method);
      if (handler == null) {
        handler = MethodHandler.create(this, method);
        methodHandlerCache.put(method, handler);
      }
    }
    return handler;
  }

这里通过MethodHandler.create(this,method)创建一个MethodHandler对象,看一下是如何创建的:

  static MethodHandler<?> create(Retrofit retrofit, Method method) {
    CallAdapter<Object> callAdapter = (CallAdapter<Object>) createCallAdapter(method, retrofit);
    Type responseType = callAdapter.responseType();
    Converter<ResponseBody, Object> responseConverter =
        (Converter<ResponseBody, Object>) createResponseConverter(method, retrofit, responseType);
    RequestFactory requestFactory = RequestFactoryParser.parse(method, responseType, retrofit);
    return new MethodHandler<>(retrofit, requestFactory, callAdapter, responseConverter);
  }
首先创建一个CallAdapter,保存CallAdapter对象的type, 创建一个Converter对象,最后new一个MethodHandler对象。

在这里要特别注意创建的CallAdapte和Converter对象,这个在后面都要用到的。

CallAdapter的创建过程如下:

  private static CallAdapter<?> createCallAdapter(Method method, Retrofit retrofit) {
    Type returnType = method.getGenericReturnType();
    if (Utils.hasUnresolvableType(returnType)) {
      throw Utils.methodError(method,
          "Method return type must not include a type variable or wildcard: %s", returnType);
    }
    if (returnType == void.class) {
      throw Utils.methodError(method, "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 Utils.methodError(e, method, "Unable to create call adapter for %s", returnType);
    }
  }
然后:

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

    StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
        .append(returnType)
        .append(". Tried:");
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
      builder.append("\n * ").append(adapterFactories.get(i).getClass().getName());
    }
    if (skipPast != null) {
      builder.append("\nSkipped:");
      for (int i = 0; i < start; i++) {
        builder.append("\n * ").append(adapterFactories.get(i).getClass().getName());
      }
    }
    throw new IllegalArgumentException(builder.toString());
  }
可以发现这个CallAdapter对象是通过这条语句来创建的:adapterFactories.get(i).get(returnType, annotations, this);

那么这条语句究竟执行的是什么呢?实际上adapterFactories.get(i)获得的正是我们上面ExecutorCallAdapterFactory或者DefaultCallAdapter.FACTORY 对象,我们就以ExecutorCallAdapterFactory为例来说明,看一下它的get()方法:

  public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (Utils.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);
      }
    };
  }
在这里会new一个 CallAdapter对象,这个对象在后面将有重要作用,我们先放一放。

再看一下Converter的创建过程:

  private static Converter<ResponseBody, ?> createResponseConverter(Method method,
      Retrofit retrofit, Type responseType) {
    Annotation[] annotations = method.getAnnotations();
    try {
      return retrofit.responseConverter(responseType, annotations);
    } catch (RuntimeException e) { // Wide exception range because factories are user code.
      throw Utils.methodError(e, method, "Unable to create converter for %s", responseType);
    }
  }
然后:

  public <T> Converter<ResponseBody, T> responseConverter(Type type, Annotation[] annotations) {
    checkNotNull(type, "type == null");
    checkNotNull(annotations, "annotations == null");

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

    StringBuilder builder = new StringBuilder("Could not locate ResponseBody converter for ")
        .append(type)
        .append(". Tried:");
    for (Converter.Factory converterFactory : converterFactories) {
      builder.append("\n * ").append(converterFactory.getClass().getName());
    }
    throw new IllegalArgumentException(builder.toString());
  }
可以看到它现获取method的返回值类型type以及注解,最后调用我们定义的converyerFactory的fromResponseBody方法来生成一个Converter对象,这个对象用语将返回的json字符串转换为对应的type类型。

接着上面的来讲,我们成功创建好了CallAdapter对象后,这个对象是在哪儿被用到了呢?

回到动态代理的位置,打开methodHandler.invoke()方法:

  Object invoke(Object... args) {
    return callAdapter.adapt(new OkHttpCall<>(retrofit, requestFactory, responseConverter, args));
  }
就在这个地方调用这个callAdapter的adapt方法,这个方法是 将OKHttpCall对象转变成我们所需要的Call对象,然后调用enqueue()或者excute()方法来发起网络请求。

这里的adapt()方法在上面创建CallAdapter的时候出现过,源码如下:

@Override public <R> Call<R> adapt(Call<R> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }
也就是说最终返回的Call就是此处new的一个ExecutorCallbackCall的对象,当它调用enqueue方法的时候执行如下:

    @Override public void enqueue(Callback<T> callback) {
      delegate.enqueue(new ExecutorCallback<>(callbackExecutor, callback));
    }
也就是还是调用的是okHttpCall的enqueue方法,源码如下:

  @Override public void enqueue(final Callback<T> callback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed");
      executed = true;
    }

    com.squareup.okhttp.Call rawCall;
    try {
      rawCall = createRawCall();
    } catch (Throwable t) {
      callback.onFailure(t);
      return;
    }
    if (canceled) {
      rawCall.cancel();
    }
    this.rawCall = rawCall;

    rawCall.enqueue(new com.squareup.okhttp.Callback() {
      private void callFailure(Throwable e) {
        try {
          callback.onFailure(e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

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

      @Override public void onFailure(Request request, IOException e) {
        callFailure(e);
      }

      @Override public void onResponse(com.squareup.okhttp.Response rawResponse) {
        Response<T> response;
        try {
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
        callSuccess(response);
      }
    });
  }
首先创建一个rawCall,看下它的内容:

  private com.squareup.okhttp.Call createRawCall() {
    return retrofit.client().newCall(requestFactory.create(args));
  }
很明显这里就是调用OkHttpClient的newCall()方法,然后再调用这个rawCall的enqueue方法,可以看出Retrofit的底层还是调用的OkHttpClient的内容,只不过做了一些封装而已。

到此关于Retrofit的原理分析完毕~

总结一下:

使用Retrofit主要分为三步,第一步通过Retrofit.Builder构造者构造一个Retrofit对象,在这里面主要来给Retrofit中的属性client、ConverterFactory、base_url来赋初始值,然后调用build()方法完成构建,在build()中主要做了两件事,一是创建一个CallAdapter.Factory对象并放倒List中保存,二是建一个用于存放Converter.Factory的List。

第二步就是执行这个retrofit.create()方法,在这个方法中首先创建创建一个MethodHandler对象,在创建MethodHandler的过程中通过上一步的CallAdapter.Factory对象来创建一个CallAdapter对象,然后通过Converter.Factory的fromResponseBody()方法来创建一个Converter对象,放倒之前创建的List中保存。

第三步,当我们去执行具体方法的时候,实际上会调用到这个CallAdapter的adapt(call)方法,它的参数是一个OkHttpCall,这个方法会返回一个新的Call对象ExecutorCallbackCall,ExecutorCallbackCall可以理解为在OkHttpCall外面包了一层,它持有原来的OkHttpCall对象。然后当我们去调用enqueue方法的时候,在这里实际上会调用内部的OkHttpCall对象的enqueue()方法,OkHttpCall的enqueue方法中回去调用okHttpClient的newCall方法创建一个call,然后再去调用这个新call的enqueue方法。这样最终将我们的请求交给了底层的OkHttpClient来处理。

猜你喜欢

转载自blog.csdn.net/wei_lei/article/details/77681408