老三长谈之Retrofit源码分析

来源:互联网 发布:ubuntu开机grub命令行 编辑:程序博客网 时间:2024/05/02 04:17
#老三长谈之Retrofit源码分析>用了Retrofit大半年了,源码看了好几次。今天我来总结一下吧,以后不看他的源码了。好记性不入烂笔头!!!  ##在没有开源框架的日子我们先来看一下没有HTTP框架以前,我们是如何做请求的。  ![](https://i.imgur.com/RgoblZN.png)1.首先build request参数  2.因为不能在主线程请求HTTP,所以你得有个Executer或者线程  3.enqueue后,通过线程去run你的请求  4.得到服务器数据后,callback回调给你的上层。  大概是以上4大步骤,在没有框架的年代,想要做一次请求,是万分痛苦的,你需要自己管理线程切换,需要自己解析读取数据,解析数据成对象,切换回主线程,回调给上层。  这种刀耕火种的原始时代,我们就不要在项目的时候去使用了。效率太低了现在市面上比较火的开源框架是Retrofit,让我们看看,学习一下他的源码.  首先先去下载他的源码吧  https://github.com/square/retrofit/tree/e6a7cd01657670807bed24f6f4ed56eb59c9c9ab  Retrofit大概流程图:![](https://i.imgur.com/Sqg6AAW.png)  Retrofit的基本使用<Pre>Retrofit retrofit = new Retrofit.Builder()                .baseUrl(url)                .addConverterFactory(GsonConverterFactory.create())                .build();</pre>所有东西都是先看构造器的  1.通过Retrofit来build一个retrofit对象 使用的是建造者模式  为我们方便的建立一个复杂的对象<pre>    public Builder() {      this(Platform.get());    }</pre><pre>  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) {        return new Android();      }    } catch (ClassNotFoundException ignored) {    }    try {      Class.forName("java.util.Optional");      return new Java8();    } catch (ClassNotFoundException ignored) {    }    return new Platform();  }</pre>  <Pre>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();        //这里默认设置ExecutorCallAdapter      return new ExecutorCallAdapterFactory(callbackExecutor);    }    static class MainThreadExecutor implements Executor {        //底层使用handler来进行跳转      private final Handler handler = new Handler(Looper.getMainLooper());      @Override public void execute(Runnable r) {        handler.post(r);      }    }  }</pre>上面代码是对retrofit对象的分析对于一个call的建立<pre>IpService ipService = retrofit.create(IpService.class);</pre>使用了门面模式,一个create包含了很多神操作!![](https://i.imgur.com/HsTDwnw.png)  图片看不清晰没所谓,我还会一步一步解析:  <pre> Utils.validateServiceInterface(service);//验证是否为接口    if (validateEagerly) {      eagerlyValidateMethods(service);//这里有个缓存校验  详情看下面    }</pre> <pre>  private void eagerlyValidateMethods(Class<?> service) {    Platform platform = Platform.get();    for (Method method : service.getDeclaredMethods()) {      if (!platform.isDefaultMethod(method)) {//看一下是否是平台的代码 如果是  就执行下一步            loadServiceMethod(method);      }    }  }</pre>下面方法使用了代理模式,对解耦 但是对性能有点影响<Pre>return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },        new InvocationHandler() {            //获取不同平台,因为支持java Android(不同版本)  对应有不同的API          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)) {                //判断这个方法是否是平台里面的默认方法  我们自己写的API不会走这个流程              return platform.invokeDefaultMethod(method, service, proxy, args);            }            //这里是解析过程     解析注解,传参,把他封装成我们常用的request            ServiceMethod<Object, Object> serviceMethod =                (ServiceMethod<Object, Object>) loadServiceMethod(method);            //使用OKhttp 把我们的serviceMethod做为request去访问网络            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);            return serviceMethod.callAdapter.adapt(okHttpCall);          }        });</pre><pre>  ServiceMethod<?, ?> loadServiceMethod(Method method) {    ServiceMethod<?, ?> result = serviceMethodCache.get(method);//在Retrofit内部存在一个serviceMethodCache,主要作用是对各种service的那个指定的方法进行缓存,避免重复加载,比较反射挺耗性能的    if (result != null) return result;    synchronized (serviceMethodCache) {      result = serviceMethodCache.get(method);      if (result == null) {        result = new ServiceMethod.Builder<>(this, method).build();        serviceMethodCache.put(method, result);//如果没有就往里面添加      }    }    return result;  }</pre>那么ServiceMethod是如何构建<pre>public ServiceMethod build() {      callAdapter = createCallAdapter();//这里你就可以回调器Retrofit建立的时候需要传进来的CallAdapter,尽管也有默认的      responseType = callAdapter.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();//GSON或xml之类的向对象所需的东西开始转换      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);    }</pre>然后我们正则method解析完成在于<pre>    //这里是解析过程解析注解,传参,把他封装成我们常用的request    ServiceMethod<Object, Object> serviceMethod = ServiceMethod<Object, Object>) loadServiceMethod(method);//详情请看上面的代码</pre>然后需要执行网络访问,我们都知道Retrofit是基于Okhttp的,那么到底是为什么呢?<pre>//使用OKhttp 把我们的serviceMethod做为request去访问网络      OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);      return serviceMethod.callAdapter.adapt(okHttpCall);</pre>serviceMethod.callAdapter.adapt(okHttpCall)callAdapter的adapt方法前面讲过,它会创建ExecutorCallbackCall,ExecutorCallbackCall的部分代码如下所示。<Pre> 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>() {//可以看出ExecutorCallbackCall是对Call的封装,它主要添加了通过callbackExecutor将请求回调到UI线程。 ExecutorCallbackCall的enqueue方法最终调用的是delegate的enqueue方法        @Override public void onResponse(Call<T> call, final Response<T> response) {          callbackExecutor.execute(new Runnable() {            @Override public void run() {              if (delegate.isCanceled()) {                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);            }          });        }      });    }</pre>这就是Retrofit的大概流程。(其实挺简单)我总结一下吧:首先用Retrofit来build一个retrofit对象 使用的是建造者模式。这个retrofit对象对象,可以定义我们怎么样回调,怎么样去解析我们获得的数据,一些baseurl之类的属性,然后使用门面模式retrofit.create(IpService.class)方便我们使用者去调用方法,动态代理获取serviceMethod.callAdapter.adapt(okHttpCall),然后把返回的结构,可能通过解析后传递给我们用户