《Retrofit源码解析之请求流程概述》简单的对Retrofit的请求流程做了梳理:从该篇文章中我们知道Retrofit是通过Convert来完成数据解析转换的:

//ServiceMethod的方法
R toResponse(ResponseBody body) throws IOException {//Converter对象 return responseConverter.convert(body);}

本文就以Gson作为数据转换类简单的介绍Converter是怎么工作的。
So,让我们开车吧!咳,让我们开始吧。

Retrofit在内部帮我们将服务器返回的数据进行了解析,数据解析的目的无非就是将一种数据源转换成另外一种数据类型,所以Retrofit将此行为抽象成了一个接口:

//F源数据,T解析后返回的数据类型
public interface Converter<F, T> {T convert(F value) throws IOException;
}

常规情况下我们只对服务器返回的数据源解析成我们的需要的数据就可以了,在Okhttp中服务器返回的数据源就是ResponseBody对象。所以我们的目标就是对ResponseBody进行解析:

T convert(ResponseBody value){//do convert and return t
}

其实Retrofit考虑的远远比我们的多,不仅可以对ResponseBody进行转换,也可以对RequestBody进行转换;具体其内部提供了一个Convert.Factory:

abstract class Factory {//对ResponseBody进行数据转换的转换器public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type,Annotation[] annotations, Retrofit retrofit) {return null;}//将未知数据转换成RequestBody的转换器public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type,Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {return null;}//将未知数据转换成String类型的数据转换器public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations,Retrofit retrofit) {return null;}
}

我们知道,如果要Retrofit要使用Gson作为数据转换器的话,在初始化Retrofit的时候需要添加这么一个代码:

Retrofit retrofit = new Retrofit.Builder().baseUrl("http://www.xxx.xxx")  .addConverterFactory(GsonConverterFactory.create()) //添加Gson.build();

此篇博文的主旨就是看看这玩意内部的具体原理.,不用说GsonConvertFactory实现了Convert.Factory(Convert.Factoy的具体作用就是获取一个Convert)。其create方法如下:

  public static GsonConverterFactory create() {return create(new Gson());}public static GsonConverterFactory create(Gson gson) {return new GsonConverterFactory(gson);}class GsonConverterFactory extends Converter.Factory{//持有一个gson对象用来讲原始数据转换成JavaBeanprivate final Gson gson;private GsonConverterFactory(Gson gson) {this.gson = gson;}}

所以我们来看看GsonConverterFactory 是怎么对ResponseBody 进行JavaBean的转换的吧:

 //GsonConverterFactory 类的工厂方法,返回一个Converter对象public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,Retrofit retrofit) {//Gson的数据转换器TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));return new GsonResponseBodyConverter<>(gson, adapter);}

responseBodyConverter方法需要根据type类型来返回一个对应的Gson的TypeAdapter对象交给GsonResponseBodyConverter这个转换器,进入其convet方法看看:

public T convert(ResponseBody value) throws IOException {//拿到ResponseBody的数据流JsonReader jsonReader = gson.newJsonReader(value.charStream());//Gson将数据转换成JavaBenreturn adapter.read(jsonReader);}

还是很简单的逻辑:
1、拿到ResopnseBody的真实数据流
2、交给Gson的JsonReader进行处理
3、调用Adapter的read方法返回对应的JavaBean
关于TypeAdapter的详细使用,可以参考博主的《Gson源码解析》

那么Retrofit是怎么知道返回值数据的真实类型的呢?
我们知道java中一个对象是封装成Method对象的:

 //根据Method对象获取对应method的返回值类型Type returnType = method.getGenericReturnType();

其实这个拿到的是一个Call<T>类型的对象,是拿不到T具体的T对象的,为此
在ServiceMethod的createAdapter方法中对接口方法做了处理(详情见):

  private CallAdapter<T, R> createCallAdapter() {//获取方法的放回值类型Type returnType = method.getGenericReturnType();Annotation[] annotations = method.getAnnotations();//将returnType 交给 一个CallAdapterreturn (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);}

上面的returnType已经辗转之后具体在Retrfoit中交给了ExecutorCallAdapterFactory,对ReturnType做了进一步的解析来获取真正的javaBean类型:

 //ExecutorCallAdapterFactory的get方法public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {//获取真正的JavaBean类型,比如Call<T> 则返回T的type对象 final Type responseType = Utils.getCallResponseType(returnType);return new CallAdapter<Object, Call<?>>() {@Override public Type responseType() {return responseType;}@Override public Call<Object> adapt(Call<Object> call) {return new ExecutorCallbackCall<>(callbackExecutor, call);}};}

所以总体上Retrofit的执行逻辑可以总结如下:
1、拿到某个ApiService方法的返回值JavaBean类型returnType(具体见ServiceMethod的createAdapter方法)
2、根据返回值的信息,通过ConvertFactory找到一个对应的Converter
3、将Okhttp的数据源 转换成returnType类型的数据


其实读到此处还有一个问题没有深究:比如Retrofit怎么定位到某个方法返回值使用的是哪个Converter对象的呢?下面就来仔细分析这个流程。
以下面代码为例,看看Retrofit都做了些什么:

Retrofit retrofit = new Retrofit.Builder().baseUrl("http://www.xxx.xxx")  .addConverterFactory(GsonConverterFactory.create()) //添加Gson.build();//其addConverterFactory方法在Retrofit.Builder类里面如下://持有private final List<Converter.Factory> converterFactories = new ArrayList<>();public Builder addConverterFactory(Converter.Factory factory) {converterFactories.add(checkNotNull(factory, "factory == null"));return this;}

最终Builder的converterFactories这个集合在build方法构建Retrofit的时候做了如下处理:

   List<Converter.Factory> converterFactories =new ArrayList<>(1 + this.converterFactories.size());//添加一个默认的 BuiltInConverters对象converterFactories.add(new BuiltInConverters());converterFactories.addAll(this.converterFactories);

这段代码除了把用户自定义的Converter.Factory注入到集合中之外,还在集合的第一个位置插入了BuiltInConverters这个默认的Converter.Factory对象。那么Retrofit是如何在这个集合里面定位到自己所需的Converter.Factory的呢?
在《Retrofit之OkhttpCall执行原理详解》一文中我们知道在每个请求执行的时候都需要创建一个ServiceMethod对象,而且每个方法执行的时候都需要最终调用toResponse方法来进行对ResponseBody进行转换:

 R toResponse(ResponseBody body) throws IOException {return responseConverter.convert(body);}

那么responseConverter这个Converter对象是怎么初始化的就是回答上面问题的关键所在,追踪在代码发现其初始化ServiceMethod.Builder方法的createResponseConverter进行初始化的:

  private Converter<ResponseBody, T> createResponseConverter() {//获取方法的注解信息Annotation[] annotations = method.getAnnotations();//返回Converter对象return retrofit.responseBodyConverter(responseType, annotations);}

如上所示,拿到注解和最终数据返回值类型之后交给了retrofit.responseBodyConverter,需要注意的是这个responseType就是Call<T>的T。还得进入Retrofit的responseBodyConverter方法进行查看,最终定位方法如下:

 public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {return nextResponseBodyConverter(null, type, annotations);}public <T> Converter<ResponseBody, T> nextResponseBodyConverter(@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {int start = converterFactories.indexOf(skipPast) + 1;//对Converter.Factory集合进行遍历for (int i = start, count = converterFactories.size(); i < count; i++) {Converter<ResponseBody, ?> converter =converterFactories.get(i).responseBodyConverter(type, annotations, this);if (converter != null) {return (Converter<ResponseBody, T>) converter;}}//省略部分代码}

nextResponseBodyConverter方法做的核心工作就是遍历Converter.Factory的集合,然后调用Factory对象的responseBodyConverter,如果该方法的返回值不为null则确认匹配成功并立即终止循环。其实最最核心的匹配原则是根据returenType进行匹配一个conveter对象的。

Retrofit没有写类似的if-else这些硬编码来过滤需要哪个Converter,而是设计了一个工厂类,通过通过模式来完成Converter对象的创建。这点还是很牛叉的,因为通过我们只需要添加自己所需要的工厂类即可,可插拔性极强。事实上Retrofit自己提供了好多Converter.Factory的实现,如下图,第一个就是我们熟悉的GsonConverterFactory对象的实现:

简单的用一个图片来作为本篇博文的总结:

到此为止Retrofit对服务器返回的数据转换内部原理就讲解完毕,如果不对的地方,欢迎批评指正。
在此遗留一个问题,前面说过Converter.Factory添加了一个默认的BuiltInConverters对象,这个对象的作用是神马呢?后面在分析。

根据《Retrofit源码解析之请求流程概述》我们知道Retrofit通过OkhttpCall来完成同步或者异步请求,那么OkhttpCall的execute和enqueue方法是什么时候开始执行的呢?答案在下一篇博客

Retrofit之Converter简单解析相关推荐

  1. Rxjava、Retrofit返回json数据解析异常处理

    每个App都避免不了要进行网络请求,从最开始的用谷歌封装的volley到再到android-async-http再到OKHttpUtils再到现在的Retrofit和RxJava,从我自己用后的体验来 ...

  2. 插件化框架DL源码的简单解析

    目前行业内已经有较多的插件化实现方案.本文主要对DL(DynamicLoadApk)这一个开源的侵入式插件化方案进行简单分析.因为Service组件插件化的实现逻辑和Activity大体相似,所以在这 ...

  3. java 解析xls 文件_java简单解析xls文件的方法示例【读取和写入】

    本文实例讲述了java简单解析xls文件的方法.分享给大家供大家参考,具体如下: 读取: import java.io.*; import jxl.*; import jxl.write.*; imp ...

  4. [ 转载 ] Java基础10--关于Object类下所有方法的简单解析

    关于Object类下所有方法的简单解析 类Object是类层次结构的根类,是每一个类的父类,所有的对象包括数组,String,Integer等包装类,所以了解Object是很有必要的,话不多说,我们直 ...

  5. java在线打开xml文件_java实现简单解析XML文件功能示例

    本文实例讲述了java实现简单解析XML文件功能.分享给大家供大家参考,具体如下: package demo; import java.io.File; import java.io.IOExcept ...

  6. java:AXIS调用webService接口,返回String类型xml,并用dom4j简单解析xml

    一.使用axis调用webService接口,返回String类型xml 1.导入axis依赖 2.直接贴代码 /*** 调用webservice接口的方法,并返回String类型的xml* @par ...

  7. HTML-HTML协议简单解析

    HTML-HTML协议简单解析 在浏览器访问一个地址: 127.0.0.1:7890/html/html.htm //代表访问当地服务器路径下的/html的html.htm文件 客户端发送的请求命令是 ...

  8. C++生成LNK文件及LNK文件简单解析

    C++生成LNK文件及LNK文件简单解析 话不多说,直接上代码吧. 生成快捷方式代码: int CreateLnk(const wchar_t* TARGET, const wchar_t* LNKF ...

  9. 大数据培训课程数据清洗案例实操-简单解析版

    数据清洗(ETL) 在运行核心业务MapReduce程序之前,往往要先对数据进行清洗,清理掉不符合用户要求的数据.清理的过程往往只需要运行Mapper程序,不需要运行Reduce程序.大数据培训 数据 ...

  10. 邻近算法(KNN)原理简单解析

    邻近算法(KNN)原理简单解析 一.什么是邻近算法 1.1简介 1.2核心思想 1.3 算法流程 1.4 优缺点 二.实例演示KNN算法 一.什么是邻近算法 1.1简介 邻近算法,或者说K最近邻(KN ...

最新文章

  1. html前端开发是什么,web前端开发需要会什么
  2. 给热爱学习的同学们推荐一些顶级的c# Blogs链接
  3. nexys3使用笔记1
  4. 如何防止同一账号多次登录
  5. OpenCASCADE绘制测试线束:图形命令之AIS 查看器——查看命令
  6. css变换transform 以及 行内元素的一些说明
  7. Blazor University (1)介绍 - 什么是 Blazor?
  8. 孩子大了真是不好管了
  9. python一图带你精通time类型转换
  10. linux container 原理,容器概念与Linux Container原理
  11. WSS(Windows Storage Server)2008R2使用指南(三)配置及使用篇
  12. PHP的几个常用加密函数
  13. 记录——《C Primer Plus (第五版)》第七章编程练习第六题
  14. Android中kt转java_将我现有的andorid工作室项目转换为kotlin?
  15. 经典参考书:《编程之美——微软技术面试心得》
  16. mysql odbc 驱动程序不支持所需的属性_ODBC 驱动程序不支持所需的属性。
  17. kafka与zookeeper下载安装及kafka常用命令
  18. 定时任务中cron表达式详解
  19. 怎么把java程序打包?java源代码打包方法
  20. SQL 2008R2 误删除数据恢复方法(一)

热门文章

  1. Java编程:排序算法——基数排序
  2. SQL:Mongoose在node中的应用
  3. C++_Operator Overloading(运算符重载 | 计算有理数的加减乘除)
  4. Django搭建的个人博客
  5. 实操教程|Pytorch - 弹性训练极简实现( 附源码)
  6. 操作给定的二叉树,将其变换为源二叉树的镜像。
  7. leetcode之回文链表
  8. spring boot 2.0.3+spring cloud (Finchley)1、搭建服务注册和发现组件Eureka 以及构建高可用Eureka Server集群...
  9. [深入React] 8.refs
  10. jQuery 学习笔记 元素操作