老三长谈之Retrofit源码分析

#老三长谈之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),
然后把返回的结构,可能通过解析后传递给我们用户

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值