Retrofit源码解析(下)
接着上一章继续分析上一章主要简单说了一下基本使用和注解,这一章,我们主要看源码,废话不多说了,直接上。先上一张图 从网络上拿来的
前面一章说了一下Retrofit的简单使用https://www.cnblogs.com/huangjialin/p/9492182.html
//创建retrofit
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url) //设置baseURl
.addConverterFactory(ScalarsConverterFactory.create()) //增加返回值为String的支持
.addConverterFactory(GsonConverterFactory.create())
.build();
ApiService apiService = retrofit.create(ApiService.class);
Call<SwitchTest> call = apiService.getInformation();
call.enqueue(new Callback<SwitchTest>() {
@Override
public void onResponse(Call<SwitchTest> call, Response<SwitchTest> response) {
Log.d("huangjialin", "---onResponse----" + response.body().getMessage());
} @Override
public void onFailure(Call<SwitchTest> call, Throwable t) {
Log.d("huangjialin", "--- 失败----" ); }
});
我们看一下new Retrofit.Builder()源码是怎么走的
 public Builder() {
       this(Platform.get());
     }
 class Platform {
   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 != ) {
         return new Android();
       }
     } catch (ClassNotFoundException ignored) {
     }
     try {
       Class.forName("java.util.Optional");
       return new Java8();
     } catch (ClassNotFoundException ignored) {
     }
     return new Platform();
   }
 //—————省略若干代码—————-
 }
从代码中可以看出来,Builder后先是调用this(Platform.get());然后在调用findPlatform()方法,在findPlatform()方法中主要进行平台的判断,不同的平台返回不同的线程池。在最新的几个版本中去掉了iOS平台的判断。
好了,回过头来我们接着看build()方法是怎么执行的
 public Retrofit build() {
       if (baseUrl == null) { //从这里这里知道baseUrl一定不能为空,也就是说必须要设置,否则会抛异常
         throw new IllegalStateException("Base URL required.");
       }
       okhttp3.Call.Factory callFactory = this.callFactory; //如果需要对OkHttpClient进行设置,则可以构建OkHttpClient对象,然后调用callFactory方法将设置好的OkHttpClient传进去。
       if (callFactory == null) {
         callFactory = new OkHttpClient();
       }
       Executor callbackExecutor = this.callbackExecutor;
       if (callbackExecutor == null) {
         callbackExecutor = platform.defaultCallbackExecutor(); //将回调传递到主线程
       }
       // adapterFactories主要用于存储对Call进行转化的对象
       List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
       callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
       //主要用于存储数据转换后的对象
       List<Converter.Factory> converterFactories =
           new ArrayList<>( + this.converterFactories.size());
       // Add the built-in converter factory first. This prevents overriding its behavior but also
       // ensures correct behavior when using converters that consume all types.
       converterFactories.add(new BuiltInConverters());
       converterFactories.addAll(this.converterFactories);
       //将retrofit对象返回来
       return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
           unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
     }
上面做的注释很清晰,也就是说build()后,我们可以拿到这个Retrofit这个对象,接着ApiService apiService = retrofit.create(ApiService.class);我们看看这句代码的源码是怎么走的
 public <T> T create(final Class<T> service) {
     //这里主要是进行一些判断验证,比如说我们这里定义的ApiService,这个只能定义为interfaces类型,而不能定义为class类型。并且interfaces不能被扩展
     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, @Nullable Object[] args)
               throws Throwable {
             // 判断方法是不是属于对象的方法
             if (method.getDeclaringClass() == Object.class) {
               return method.invoke(this, args);
             }
             //判断是否在主线程
             if (platform.isDefaultMethod(method)) {
               return platform.invokeDefaultMethod(method, service, proxy, args);
             }
             ServiceMethod<Object, Object> serviceMethod =
                 (ServiceMethod<Object, Object>) loadServiceMethod(method);
             OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
             return serviceMethod.adapt(okHttpCall);
           }
         });
   }
当进行一系列验证判断以后,Proxy.newProxyInstance来拿到一个动态代理,同时实现invoke()方法。通过当我们调用接口中的方法时,比如说调用登陆接口 Call<LoginModel> login(@Body Login login);,
这个时候就会调用InvocationHandler中的invoke方法,invoke()方法中有三个参数,第一个就是代理对象,第二个就是所调用的方法,比如说调用登陆接口,这个方法就是login,第三个就是方法参数了。
接着我们找到loadServiceMethod(method)我们看看是怎么执行的。
 ServiceMethod<?, ?> loadServiceMethod(Method method) {
     ServiceMethod<?, ?> result = serviceMethodCache.get(method);
     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;
   }
loadServiceMethod这个方法,首先进行一下判断,也就是说先从缓存中获取,看看缓存中有没有这个请求方法,如果有的话,那就直接返回,没有的话,通过new ServiceMethod.Builder<>(this, method).build();
来构建,然后在保存起来。我们看看build()中的源码
  public ServiceMethod build() {
  //调用了createCallAdapter方法,它最终会得到我们在构建Retrofit调用build方法时adapterFactories添加的对象的get方法
       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?");
       }
       //这里面通过遍历来拿到我们适合的Converter的转化对象,由于retrofit可以调用addConverterFactory添加多个,如Gson
       responseConverter = createResponseConverter();
       //这里主要是通过遍历拿到请求请求方法,如GET POST ,PUT这些
       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);
         }
         //这里获取到我们接口上面的参数注解比如说@Query @QueryMap这些
         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.");
       }
       //返回ServiceMethod对象
       return new ServiceMethod<>(this);
     }
上面这个方法主要目的就是为了拿到ServiceMethod对象。回过头来,我们继续看retrofit的create()方法
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
当拿到serviceMethod对象以后,接着就执行new OkHttpCall();来得到okHttpCall,并且最后返回serviceMethod.adapt(okHttpCall),我们进入OkHttpCall()对象看看
 final class OkHttpCall<T> implements Call<T> {
   //------省略若干代码--------
   @Override public synchronized Request request() {
     okhttp3.Call call = rawCall;
     if (call != null) {
       return call.request();
     }
     if (creationFailure != null) {
       if (creationFailure instanceof IOException) {
         throw new RuntimeException("Unable to create request.", creationFailure);
       } else if (creationFailure instanceof RuntimeException) {
         throw (RuntimeException) creationFailure;
       } else {
         throw (Error) creationFailure;
       }
     }
     try {
       return (rawCall = createRawCall()).request();
     } catch (RuntimeException | Error e) {
       throwIfFatal(e); // Do not assign a fatal error to creationFailure.
       creationFailure = e;
       throw e;
     } catch (IOException e) {
       creationFailure = e;
       throw new RuntimeException("Unable to create request.", e);
     }
   }
   @Override public void enqueue(final Callback<T> callback) {
     checkNotNull(callback, "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) {
           throwIfFatal(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) {
         Response<T> response;
         try {
           response = parseResponse(rawResponse);
         } catch (Throwable e) {
           callFailure(e);
           return;
         }
         try {
           callback.onResponse(OkHttpCall.this, response);
         } catch (Throwable t) {
           t.printStackTrace();
         }
       }
       @Override public void onFailure(okhttp3.Call call, IOException e) {
         callFailure(e);
       }
       private void callFailure(Throwable e) {
         try {
           callback.onFailure(OkHttpCall.this, e);
         } catch (Throwable t) {
           t.printStackTrace();
         }
       }
     });
   }
 //  --------省略若干代码---------
到这里,基本很明了,看过我前面的okhttp源码解析的朋友,这里就会觉得很熟悉了,这里通过实现 Call接口,然后通过request()和enqueue()这两个方法,然后将请求的结果回调回来,从而实现网络通信。
当然,这里只是retrofit一些基本的流程在源码中是这样走的,如果说要非常非常详细的源码,这不是一两篇文章能写完的,光retrofit就可以写出一本书了,当然,目前的水平,还没有达到那个地步,慢慢来。
Retrofit源码解析(下)的更多相关文章
- Retrofit源码解析(上)
		简介Retrofit是Square公司开发的一款针对Android网络请求的框架,官网地址http://square.github.io/retrofit/ ,在官网上有这样的一句话介绍retrofi ... 
- Laravel学习笔记之Session源码解析(下)
		说明:在中篇中学习了session的CRUD增删改查操作,本篇主要学习关闭session的相关源码.实际上,在Laravel5.3中关闭session主要包括两个过程:保存当前URL到session介 ... 
- RxJava + Retrofit源码解析
		RxJava + Retrofit怎么请求网络,具体的用法这里就不讲了,本文只讲一些重点源码. 版本如下: okhttp : "com.squareup.okhttp3:okhttp:3.1 ... 
- axios 源码解析(下) 拦截器的详解
		axios的除了初始化配置外,其它有用的应该就是拦截器了,拦截器分为请求拦截器和响应拦截器两种: 请求拦截器 ;在请求发送前进行一些操作,例如在每个请求体里加上token,统一做了处理如果以后要 ... 
- Retrofit源码设计模式解析(上)
		Retrofit通过注解的方法标记HTTP请求参数,支持常用HTTP方法,统一返回值解析,支持异步/同步的请求方式,将HTTP请求对象化,参数化.真正执行网络访问的是Okhttp,Okhttp支持HT ... 
- Spring源码解析系列汇总
		相信我,你会收藏这篇文章的 本篇文章是这段时间撸出来的Spring源码解析系列文章的汇总,总共包含以下专题.喜欢的同学可以收藏起来以备不时之需 SpringIOC源码解析(上) 本篇文章搭建了IOC源 ... 
- Retrofit源码设计模式解析(下)
		本文将接着<Retrofit源码设计模式解析(上)>,继续分享以下设计模式在Retrofit中的应用: 适配器模式 策略模式 观察者模式 单例模式 原型模式 享元模式 一.适配器模式 在上 ... 
- erlang下lists模块sort(排序)方法源码解析(二)
		上接erlang下lists模块sort(排序)方法源码解析(一),到目前为止,list列表已经被分割成N个列表,而且每个列表的元素是有序的(从大到小) 下面我们重点来看看mergel和rmergel ... 
- erlang下lists模块sort(排序)方法源码解析(一)
		排序算法一直是各种语言最简单也是最复杂的算法,例如十大经典排序算法(动图演示)里面讲的那样 第一次看lists的sort方法的时候,蒙了,几百行的代码,我心想要这么复杂么(因为C语言的冒泡排序我记得不 ... 
随机推荐
- Netty 零拷贝(一)Linux 零拷贝
			Netty 零拷贝(一)Linux 零拷贝 本文探讨 Linux 中主要的几种零拷贝技术以及零拷贝技术适用的场景. 一.几个重要的概念 1.1 用户空间与内核空间 操作系统的核心是内核,独立于普通的应 ... 
- url地址   参数 带 参数 注意事项 , chain  ,  redirect  ,  redirectAction
			当 url 地址中含有 参数 时 ,若参数值是一个 含有 参数的 地址时 , 应警惕 ,如 index/goIndex!login?backUrl=/shop/goShop!go?a1=1& ... 
- 新电脑的操作系统win10的所有设置问题汇总
			上来改的win7发现很多驱动没法装,装了也不能用,后来只能改win10了,另外win7的风扇声音也很大. 1.关闭win10自动更新.在服务里面禁用winupdate 2.注销改成了点头像,然后点注销 ... 
- php连接DB2
			在php.ini中添加对DB2的支持 //////////////////////////////////////////////////// ;;;;;;;;;;;;;;;;;;;;;; ; Dyn ... 
- Django介绍(3)
			https://www.cnblogs.com/yuanchenqi/articles/5786089.html 
- excel绝对引用中间添加符号
			=F1&"_"&J1 绝对引用 相对引用 按F4 然后复制全部,选择性黏贴,值和数字即可 
- (网络流)ACM Computer Factory --POJ --3436
			链接: http://poj.org/problem?id=3436 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=82835#probl ... 
- 用Lucene实现分组,facet功能,FieldCache
			假如你像用lucene来作分组,比如按类别分组,这种功能,好了你压力大了,lucene本身是不支持分组的. 当你想要这个功能的时候,就可能会用到基于lucene的搜索引擎solr. 不过也可以通过编码 ... 
- 磁盘配额(Quota)的应用与实践
			1>什么是Quota 在Linux中,由于是多用户,多任务的环境,所以会有多用户共同使用一个硬盘空间的情况发生,如果其中有少数几个用户大量占用掉了硬盘空间的话,那肯定影响其他用户的使 ... 
- 【转】【译】在 Windows 10 应用程序中注册任意依赖属性的改变
			原文地址:http://visuallylocated.com/post/2015/04/01/Registering-to-any-DependencyProperty-changing-in-Wi ... 
