>【版权申明】非商业目的注明出处可自由转载

博文地址:https://blog.csdn.net/ShuSheng0007/article/details/89675797

出自:shusheng007

系列文章

秒懂的Retrofit2源码详解​blog.csdn.net用Retrofit+RxJava2封装优雅的网络请求框架​blog.csdn.net秒懂Retrofit2之GsonConverter​blog.csdn.net

@[toc]

概述

Retrofit2 已经成为Android开发中网络请求方面当之无愧的扛把子了,我们很有必要对自己经常使用的东西有个较为深入的理解。

Retrofit2 中有两个非常精彩的设计:ConverterCallAdapter, 通过这两个接口,Retrofit2的可扩展性被极大的增强了,用户可以根据需求自由扩展。我们这篇文章就对Converter做一个比较深入的解析。

作用

例如我们有如下代码片段:其中UserPerson 是两个自定义类

@POSTObservable<List<User>>method1(@Body Person rBody);

那么retrofit2是怎么认识我们自定义的类呢?这就是Converter 要干的事情。

下面是 Converter接口的源代码:

//将F类型的值转化为T类型的值
public interface Converter<F, T> {T convert(F value) throws IOException;abstract class Factory {//将API方法的返回类型从ResponseBody 转换为type,type是由CallAdapter 接口里面的responseType()函数返回的。public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type,Annotation[] annotations, Retrofit retrofit) {return null;}//将API方法的输入参数类型从 type转换为ResponseBody , 用于转换被注解@Body, @Part 和 @PartMap标记的类型public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type,Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {return null;}//将API方法的输入参数类型从 type 转换为String,用于转换被注解 @Header, @HeaderMap, @Path, @Query 和 @QueryMap 标记的类型public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations,Retrofit retrofit) {return null;}//下面是两个工具方法protected static Type getParameterUpperBound(int index, ParameterizedType type) {return Utils.getParameterUpperBound(index, type);}protected static Class<?> getRawType(Type type) {return Utils.getRawType(type);}}
}

通过其源码可见其只有一个方法 T convert(F value),就是将F类型的value转换为T类型的输出值。不同的Converter可以通过其内部类Factory得到。

使用原理

那么converter是如果作用于retrofit2的呢? 我们可以在retrofit2的源码中搜索 T convert(F value)的引用,如下图所示.我们可以发现 Converter的使用只有两种场景:

第一:红框中,使用Converter 将我们使用okhttp3 这个库发起HTTP请求的返回值的类型(RequestBody)转换为我们自定义的类型(T)。 针对我们上面的示例代码为:将RequestBody类型转换为List<User>类型

第二:蓝框中,使用Converter 将我们的输入参数类型从自定义类型转换为RequestBody 或者String。 针对我们上面的示例代码为:将Person类型转换为RequestBody 类型

因为retrofit2在代码中是针对Converter 这个接口编程的,所以我们就可以为这个接口提供很多种具体的实现。Retrofits2中有一个默认的实现BuiltInConverters,让我们来看一下:

final class BuiltInConverters extends Converter.Factory {//做的工作很简单,这里要求方法返回值类型type必须为ResponseBody或者Void,转化后的类型为ResponseBody。//返回相应的Converter实例,其他的类型都处理不了,直接返回null//当方法返回值类型type是ResponseBody时检查一下方法是否使用了@Streaming注解标识,如果没有标识则将数据全部读取到内存中,返回一个ResponseBody@Overridepublic Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {if (type == ResponseBody.class) {return Utils.isAnnotationPresent(annotations, Streaming.class)? StreamingResponseBodyConverter.INSTANCE: BufferingResponseBodyConverter.INSTANCE;}if (type == Void.class) {return VoidResponseBodyConverter.INSTANCE;}return null;}//更简单,要求方法的请求参数type必须为RequestBody类型,得到的类型也是RequestBody,没有做任何类型转换,//返回相应的Converter实例,其他的类型都处理不了,直接返回null@Overridepublic Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {if (RequestBody.class.isAssignableFrom(Utils.getRawType(type))) {return RequestBodyConverter.INSTANCE;}return null;}//将object转成Stringstatic final class ToStringConverter implements Converter<Object, String> {static final ToStringConverter INSTANCE = new ToStringConverter();@Override public String convert(Object value) {return value.toString();}}...static final class VoidResponseBodyConverter implements Converter<ResponseBody, Void> {static final VoidResponseBodyConverter INSTANCE = new VoidResponseBodyConverter();@Override public Void convert(ResponseBody value) {value.close();return null;}}static final class RequestBodyConverter implements Converter<RequestBody, RequestBody> {static final RequestBodyConverter INSTANCE = new RequestBodyConverter();@Override public RequestBody convert(RequestBody value) {return value;}}//如果使用Streaming注解标记了方法,则使用这个转换器直接返回responseBody类型的数据,不读取到内存static final class StreamingResponseBodyConverterimplements Converter<ResponseBody, ResponseBody> {static final StreamingResponseBodyConverter INSTANCE = new StreamingResponseBodyConverter();@Override public ResponseBody convert(ResponseBody value) {return value;}}//如果不使用Streaming注解标记方法,则将返回值读取到内存中static final class BufferingResponseBodyConverterimplements Converter<ResponseBody, ResponseBody> {static final BufferingResponseBodyConverter INSTANCE = new BufferingResponseBodyConverter();@Override public ResponseBody convert(ResponseBody value) throws IOException {try {// Buffer the entire body to avoid future I/O.return Utils.buffer(value);} finally {value.close();}}}
}

上面代码非常简单,在其中关键的两个方法上我也加了很详细的注释,没有太多可以解释的。其中值得注意的是那个stringConverter,由于没有对入参的依赖,所以没有采用实现Converter.Factory里面的

public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations,Retrofit retrofit) {return null;}

这种方式来实现。

通过以上源码我们可以解释很多Retrofit2的行为,例如 1:如果不添加自定义Converter,我们在定义方法时方法的入参的类型只能是RequestBody或者String,而返回值的泛型参数类型也只能是RequestBody 或者Void的现象。 2:如果不使用@Stream 注解标识方法,那么下载大文件时会发生OOM的问题,因为其会将返回数据一次性载入内存中。

如果是仅仅使用默认的Converter的话Retrofit2的使用将会受到极大的限制,但大神们是不允许这样的事发生的,所以我们可以自由使用各种Converter来满足我们的需求,再一次感受到了面向抽象编程的强大。

日常开发中最为常用的就是GsonConverter,但是现实中绝不仅仅只有GsonConverter,还有guava、jackson、java8、jaxb、moshi、protobuf、scalars、simplexml、wire 等Converter,如果别人写好的Converter不能满足我们的需求,那我们就需要自己写一个。

关于GsonConverter 请查看秒懂Retrofit2之GsonConverter

总结

可见一个设计优良的类库,会给用户很大的扩展空间,这一点我们应该多加学习。

下一篇讲下CallAdapter

retrofit2使用详解_秒懂Retrofit2之Converter相关推荐

  1. Spring事务管理详解_基本原理_事务管理方式

    Spring事务管理详解_基本原理_事务管理方式 1. 事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,使用JDBC的事务管理机制,就是利用java.sql.Connection对象 ...

  2. realloc重分配内存详解_羽夜水之灵_百度空间

    realloc重分配内存详解_羽夜水之灵_百度空间 realloc重分配内存详解_羽夜水之灵_百度空间 realloc重分配内存详解 最近在写source code时需要在数组的buffer小时重新申 ...

  3. python count函数代码_python count函数用法详解_后端开发

    fgetc函数的作用详解_后端开发 fgetc函数的作用是从指定文件读入一个字符,要求文件的打开方式必须是以读或读写的方式或者追加的方 式,只写方式是不能读的. 在python中可以使用"c ...

  4. python中split啥意思_python中split的用法详解_后端开发

    如何用python正则表达式匹配字符串?_后端开发 用python正则表达式匹配字符串的方法:1.当匹配单个位置的字符串时,可以使用[(.+?)]正则表达式来提取:2.当连续多个位置的字符串匹配时,可 ...

  5. 读Java并发编程实践记录_原子性_锁_同步容器详解_任务执行

    原子性: 单独的,不可分割的操作 不要使用过期状态值来决策当下的状态, 一定要先检查再执行(不检查, 将引发数据修改,丢失) 避免延迟初始化(懒加载: 先查看对象 == null, 然后new), 有 ...

  6. 正则表达式符号特殊详解_常用正则表达式_Java中正则表达式的使用

    正则表达式符号详解 限定符: 指定一个组件必须出现多少次才能满足. 1.使用 "*", "+", "?" 作为限定符: "*&qu ...

  7. sgd 参数 详解_代码笔记--PC-DARTS代码详解

    DARTS是可微分网络架构搜搜索,PC-DARTS是DARTS的拓展,通过部分通道连接的方法在网络搜索过程中减少计算时间的内存占用.接下来将会结合论文和开源代码来详细介绍PC-DARTS. 1 总体框 ...

  8. 名片管理系统python详解_详解Python做一个名片管理系统

    详解Python做一个名片管理系统 来源:中文源码网    浏览: 次    日期:2019年11月5日 [下载文档:  详解Python做一个名片管理系统.txt ] (友情提示:右键点上行txt文 ...

  9. java 函数fun_c语言中fun用法详解_后端开发

    Java Dao层的作用_后端开发 Dao层叫数据访问层,属于一种比较底层,比较基础的操作,可以具体到对于某个表或某个实体的增删改查,其Dao层的作用是对数据库的访问进行封装,从而不涉及业务,实现解耦 ...

最新文章

  1. vs中不得不会的一些小技巧(1)——细说查找
  2. FileZilla Server简介及使用说明
  3. 图形处理相关资源(面部识别、姿态估计、变形、、、)
  4. 论文笔记:Distilling the Knowledge
  5. 从严治码-系统集成项目之根本
  6. leetcode144. 二叉树的前序遍历(迭代)
  7. 操作系统(12)-【Linux】索引式文件系统
  8. 关于js数组的六种算法---水桶排序,冒泡排序,选择排序,快速排序,插入排序,希尔排序的理解。...
  9. 铁路查询系统c语言,铁路查询系统
  10. spingMVC post 提交乱码问题
  11. [转载]git 设置第一次输入密码之后不用输入密码
  12. jsp网页视频播放器
  13. 集成算法 | 随机森林回归模型
  14. python3读取python2的npy文件
  15. ipv4 pxe 联想start_start pxe over ipv4 和start pxe over ipv6 开机出现问题
  16. java利用复循环洗牌算法_实现不重复取数两种算法(洗牌算法)
  17. 利用计算机模拟人脑进行演绎推理,2014年4月全国自学考试计算机应用技术试题...
  18. iOS用Sketch制作APP下拉刷新的GIF动画
  19. 2021年高考高密一中成绩查询,速递|2021年高密市高中阶段学校招生录取政策发布...
  20. 卟啉基聚酰亚胺(PPBPIs);交联型卟啉基聚酰亚胺的合成(PPBPI-CRs)齐岳生物供应卟啉产品

热门文章

  1. 这些器件是电子垃圾?是艺术作品!!!
  2. 5G小科普(漫画版,So easy!)
  3. esp32 怎么分配freertos 堆栈大小_嵌入式开发入门-从STM32CudeMX、FreeRtos、Proteu仿真开始...
  4. c语言之判断电压最大值最小值,基于单片机的频率计的C语言源代码
  5. html 的c标签库,jstl C标准标签库Ⅰ
  6. 计算机会计课程试题及答案,会计电算化课后简答题及答案.doc
  7. 微型计算机字,微型计算机杂志
  8. iis同时运行asp和php,服务器IIS同时支持ASP和PHP
  9. 关闭word_Word教程第2讲:文档的基本操作(含视频)
  10. 火狐浏览器打印网页不全_武汉社保网上下载打印流程