关于Retrofit2.0源码的学习和理解

来源:互联网 发布:js 简单加密算法 编辑:程序博客网 时间:2024/06/04 18:58

    今年4月初,刚接触到RxJava、Retrofit等框架的时候,当时也是一头楞,因为我以前的项目中都是采用MVP加上Volley请求框架的结构。使用Retrofit开源框架搭建项目这个在网络上已经有很多很好的介绍了,在这里就不去探讨怎么使用。之所以要去写源码的实现,一方面呢是因为最近研读了下,对Retrofit有了一些了解,主要是另一个方面,写一写博客(当写笔记吧),一来理清下思路,二来相当于做个笔记,方便后面复习加深下印象。为了能更加清晰的分析Retrofit源码,我还是单独的写个工程,很简单。好嘞!废话不多说了,开始我们的Retrofit2.0源码理解之路吧!


1.简单配置Retrofit2.0

    在app项目下的build.gradle中添加:

compile 'com.squareup.retrofit2:retrofit:2.0.2'compile 'com.squareup.retrofit2:converter-gson:2.0.0'

    编写一个实体类:

package com.jianzou.retrofit;/** * Created by JianZou on 2016/12/19. */public class UserModel{    private String id;    private String name;    private String age;    public String getId()    {        return id;    }    public void setId(String id)    {        this.id = id;    }    public String getAge()    {        return age;    }    public void setAge(String age)    {        this.age = age;    }    public String getName()    {        return name;    }    public void setName(String name)    {        this.name = name;    }}

编写interfice类

package com.jianzou.retrofit;import java.util.List;import retrofit2.Call;import retrofit2.http.GET;import retrofit2.http.Path;/** * Created by JianZou on 2016/12/19. */public interface IRequestInter{    @GET("Users/{action}")    Call<List<UserModel>> getUsers(@Path("action") String action);}

最后去构建Retrofit

package com.jianzou.retrofit;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import java.util.List;import retrofit2.Call;import retrofit2.Callback;import retrofit2.Response;import retrofit2.Retrofit;import retrofit2.converter.gson.GsonConverterFactory;public class MainActivity extends AppCompatActivity{    @Override    protected void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //构建Retrofit        Retrofit retrofit = new Retrofit.Builder()                .baseUrl("http://www.ceshi.demo/api")//URL可以修改成自己请求的公共URL部分                .addConverterFactory(GsonConverterFactory.create())//这里使用Gson来转化返回的数据                .build();        /*        根据Java动态代理,动态的获取到每个接口的方法、参数和注解,再将这些拼接成一个request(ServiceMethod.toRequest()方法);        由OKHttp请求后返回结果,然后将返回的数据通过我们设定的GsonConverterFactory转化成Gson格式的数据;        最后,源码中设置的OkHttpCall将返回并转化成Gson格式的数据回调给UI线程。         */        IRequestInter request = retrofit.create(IRequestInter.class);        Call<List<UserModel>> call = request.getUsers("buy");        call.enqueue(new Callback<List<UserModel>>()                     {                         @Override                         public void onResponse(Call<List<UserModel>> call, Response<List<UserModel>> response)                         {                         }                         @Override                         public void onFailure(Call<List<UserModel>> call, Throwable t)                         {                         }                     }        );    }}
到这,简单的配置下就完了,再次声明:只是为了读源码而配置的这些,实际不能运行的哈!


2.源码分析

从构建Retrofit看起吧:MainActivity --> build() [ MainActivity中创建Retrofit最后面的build()方法,下文类似 ]

这里是创造者模式创建一个Retrofit,具体的代码是:

/**     * Create the {@link Retrofit} instance using the configured values.     * <p>     * Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link     * OkHttpClient} will be created and used.     */    public Retrofit build() {      if (baseUrl == null) {        throw new IllegalStateException("Base URL required.");      }      okhttp3.Call.Factory callFactory = this.callFactory;      if (callFactory == null) {        callFactory = new OkHttpClient();      }      Executor callbackExecutor = this.callbackExecutor;      if (callbackExecutor == null) {        callbackExecutor = platform.defaultCallbackExecutor();      }      // Make a defensive copy of the adapters and add the default Call adapter.      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.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);    }

从上到下看来:(1)对baseUrl做了空判断处理。(2)创建OkHttpClient()对象,这个是可以自己在new Retrofit时添加进来的,如果没有配置,默认使用OkHttpClient。(3)Executor线程执行者:在Builder这个class的构造函数中有this(Platform.get()),Platform这个类通过Java反射,判断了当前的平台,我们直接看findPlatform()中的Android()方法,

static class Android extends Platform {    @Override public Executor defaultCallbackExecutor() {      return new MainThreadExecutor();    }    @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {      return new ExecutorCallAdapterFactory(callbackExecutor);    }    static class MainThreadExecutor implements Executor {      private final Handler handler = new Handler(Looper.getMainLooper());      @Override public void execute(Runnable r) {        handler.post(r);      }    }  }
这个类默认new的是MainThreadExecutor对象,然后将这个线程放到主线程的消息队列中。通过ExecutorCallAdapterFactory中get()方法返回了final的ExecutorCallbackCall类,(4)adapterFactories,这个主要是上面call的集合,不需要关心,(5)converterFactories:这个用来将请求返回的数据进行转化以及请求中注解参数的转化。

接着看 MainActivity -->retrofit.create(IRequestInter.class);点击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);          }        });  }
这里就是用到了Java的动态代理截获接口的方法,参数名等信息。我们主要的看最后几行有效代码:

(1)创建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;  }
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();      for (Annotation annotation : methodAnnotations) {        parseMethodAnnotation(annotation);      }      if (httpMethod == null) {        throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");      }      if (!hasBody) {        if (isMultipart) {          throw methodError(              "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");        }        if (isFormEncoded) {          throw methodError("FormUrlEncoded can only be specified on HTTP methods with "              + "request body (e.g., @POST).");        }      }      int parameterCount = parameterAnnotationsArray.length;      parameterHandlers = new ParameterHandler<?>[parameterCount];      for (int p = 0; p < parameterCount; p++) {        Type parameterType = parameterTypes[p];        if (Utils.hasUnresolvableType(parameterType)) {          throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",              parameterType);        }        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];        if (parameterAnnotations == null) {          throw parameterError(p, "No Retrofit annotation found.");        }        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);      }      if (relativeUrl == null && !gotUrl) {        throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);      }      if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {        throw methodError("Non-body HTTP method cannot contain @Body.");      }      if (isFormEncoded && !gotField) {        throw methodError("Form-encoded method must contain at least one @Field.");      }      if (isMultipart && !gotPart) {        throw methodError("Multipart method must contain at least one @Part.");      }      return new ServiceMethod<>(this);    }
在ServiceMethod的build方法中:createCallAdapter()返回的实际上是Retrofit Build()方法中我们add到adapterFactories中的callAdapter,callAdapter.responseType()返回的其实就是我们传进去的UserModel类型,而createResponseConverter得到的是responseConverter对象,因为我们在创建Retrofit的时候加了这么一行addConverterFactory(GsonConverterFactory.create()),所以这里返回的是GsonConverterFactory。代码的下面就是对方法和参数注解进行了解析,这里获得到很多的parameterHandler对象,最终在ServiceMethod的toRequest方法调用中,通过parameterHandler的apply方法构造一个完整的请求。

(2)创建OkHttpCall:

OkHttpCall(ServiceMethod<T> serviceMethod, Object[] args) {    this.serviceMethod = serviceMethod;    this.args = args;  }
这一步主要是把上面创建的serviceMethod以及接口中方法的参数存在本类中。

(3)serviceMethod.callAdapter.adapt(okHttpCall):

这里的callAdapter就是上面serviceMethod.build()中createCallAdapter()返回的,而createCallAdapter最终也是通过ExecutorCallAdapterFactory中get()方法返回ExecutorCallbackCall类:

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

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;    }    @Override public void enqueue(final Callback<T> callback) {      if (callback == null) throw new NullPointerException("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()) {                // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.                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);            }          });        }      });    }    @Override public boolean isExecuted() {      return delegate.isExecuted();    }    @Override public Response<T> execute() throws IOException {      return delegate.execute();    }    @Override public void cancel() {      delegate.cancel();    }    @Override public boolean isCanceled() {      return delegate.isCanceled();    }    @SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.    @Override public Call<T> clone() {      return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());    }    @Override public Request request() {      return delegate.request();    }  }
这个类通过delegate的enqueue去请求数据,delegate对象实质上就是serviceMethod.callAdapter.adapt(okHttpCall)这行中的okHttpCall对象,由adapt()这个方法设置进去。这里面的callbackExecutor是上面Platform类Android()方法中识别在Android平台而创建的MainThreadExecutor对象,此对象存放在了主线程的消息队列,在这里执行MainThreadExecutor通过callback回调到UI线程,从而有成功onResponse和失败onFailure两个回调。接着我们看下delegate.enqueue,实际就是okHttpCall中的enqueue:

@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();        }      }    });  }
这里面有这个方法createRawCall()方法:

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;  }
createRawCall()返回okHttp3.Call对象,也就是用的okHttp3.Call对象来执行的请求。在createRawCall()中,通过serviceMethod.toRequest(args)得到请求的url,上面也提到了ServiceMethod的toRequest方法通过parameterHandler的apply方法构造一个完整的request,到此,一个请求的线路就说完了。下面接着看响应的内容:这里有一行response = parseResponse(rawResponse);

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) {      return Response.success(null, rawResponse);    }    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);    try {      T body = serviceMethod.toResponse(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;    }  }
在return的地方,T body = serviceMethod.toResponse(catchingBody);

/** Builds a method return value from an HTTP response body. */  T toResponse(ResponseBody body) throws IOException {    return responseConverter.convert(body);  }
其实就是通过serviceMethod的toResponse将请求返回的数据用我们的converter进行转化,这个转化器就是开篇我们设置进去的GsonConverterFactory。到此整个源码分析就结束了,重新整理下:我们将页面上接口传给Retrofit,Retrofit通过Java动态代理去对接口中方法和注解进行解析,在Retrofit创建的时候,根据Java平台默认创建Executor,并将此Executor存放在主线程的消息队列,在Retrofit创建中,创建了最重要的serviceMethod类,serviceMethod类将对方法和注解进行解析拼接成请求的url,并对返回的数据做转换处理。创建的OkHttpCall对象就实质上还是用的okHttp3.Call对象去执行的请求,通过serviceMethod.toRequest(args)得到的url请求,得到数据后由serviceMethod设置的转化器解析数据。最终callback以回调的方式将数据给UI界面。总算是明朗了很多,开源框架在使用的同时,看一看实现的源码,收获很多,这里的Java动态代理使用得很精髓,包括平台的判断创建线程执行的地方等等,看的过程好痛苦,但是看通了就豁然开朗了很多,但愿这对看这篇博客的朋友有一点帮助。最后谢谢大家支持!


0 0
原创粉丝点击