Retrofit原理
文章目录
- 一、前言
- 二、简单使用
- 三、整体结构
- 四、运行流程
- 五、参考链接
一、前言
Retrofit
是基于OkHttp
封装的一个框架,使其更加方便使用。目前也是使用较多的网络框架,这里对其原理进行简单记录。这里需要注意的是Retrofit
框架只是对OkHttp
的二次封装,实际的网络请求依然还是用OkHttp
进行的。因为OkHttp
的网络请求只处理网络请求,对于实际开发中涉及的其余逻辑并不关心,比如线程切换,数据解析等等。另外使用Retrofit
还可以对api的接口进行良好的管理,因此在此基础上研发了Retrofit
框架。
二、简单使用
这里简单记录一个使用例子,更多的例子可以查看官方文档和demo。
添加依赖
implementation 'com.squareup.okhttp3:okhttp:4.9.3'implementation 'com.squareup.retrofit2:retrofit:2.9.0'implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
使用方式:
interface ServerApi {@POST("s?cl=3&tn=baidutop10&fr=top1000&wd=战火中的中国驻乌克兰大使馆&rsv_idx=2&rsv_dl=fyb_n_homepage&sa=fyb_n_homepage&hisfilter=1")@FormUrlEncodedfun login(@Field("id") userId: String): Call<String>@GET("s?cl=3&tn=baidutop10&fr=top1000&wd=战火中的中国驻乌克兰大使馆&rsv_idx=2&rsv_dl=fyb_n_homepage&sa=fyb_n_homepage&hisfilter=1")fun loginObserver(): Observable<String>
}
class MainActivity : AppCompatActivity() { private val httpUrl = "http://www.baidu.com"private fun startRetrofitNet(){val retrofit = Retrofit.Builder().baseUrl(httpUrl).addConverterFactory(ScalarsConverterFactory.create())//添加gson解析.addConverterFactory(GsonConverterFactory.create())//添加字符串解析//.addCallAdapterFactory() 添加适配器转换.build()val serverApi = retrofit.create(ServerApi::class.java)val loginCall = serverApi.login("123")
// loginCall.execute()//同步方法loginCall.enqueue(object : Callback<String>{override fun onResponse(call: Call<String>, response: Response<String>) {val result = response.body()Log.e("YM--->","获取的网络内容:${result}")Toast.makeText(this@MainActivity,"--->",Toast.LENGTH_SHORT).show()}override fun onFailure(call: Call<String>, t: Throwable) {}})}
}
三、整体结构
从上文的使用方式可以看到,Retrofit
的使用方式和OkHttp
有很多不同的地方:
- 网络请求采用RESTful风格和注解的方式进行配置。这种类似于配置文件式的写法使网络请求更好的维护
- 在进行网络请求中不像
OkHttp
那样涉及到其他部分,比如Request
。这里都可以使用Retrofit
创建的对象进行链式调用进行请求。这是一种基于装饰模式的写法(跟建造者模式不是一回事,区别在于一个是根据多个参数不一样进行动态配置)。 - 在创建过程中可以通过配置
ConverterFactory
进行数据转换。因为有时候传入的数据格式不支持,比如传入一个对象,这时候可以使用转换器转换成字符串,或者将一个字符串在返回的时候转换为一个对象。 - 在创建对象的时候通过配置
CallAdapterFactory
对OkHttp
的Call
对象进行适配。在OkHttp
中Call
是用来对Request
和Response
进行处理的。这里可以看上述接口定义了两个不同的返回值,一个是Call<String>
,另外一个是RxJava的Observable<String>
。使用RxJava的话就可以调用不同的特性,这里就是使用CallAdapterFactory
进行转换的。也可以转换成kotlin这些使用方式。Retrofit
通过重新处理Call
将返回值根据实现的不同的CallAdapterFactory
做不同的转换,提高了强大的拓展性。 - 可以看到上文的响应值里面直接输出了
Toast
。要知道请求是子线程的,Toast
显示是在主线程的,所以这里自己做了线程切换。也是一个很大的不同点。这个线程切换是在Retrofit
默认的DefaultCallAdapterFactory
中做的,其它适配器里面没写的话是没有线程切换的。 - 还有一个重要的不同点从使用上看的话不好直接看出来,那就是定义接口的实例对象都被缓存起来了,防止多次调用同一个对象都去创建新的接口对象,其它的对象也有类似的操作。这里减少了部分内存占用,提高了部分内存性能(因为这个缓存是定义在
Retrofit
类里面的,所以实例对象不一样的话等于没有缓存。)。
上面就是跟OkHttp
的一些区别,那么对于Retrofit
来说,主要有以下几部分组成:
Retrofit
ConverterFactory
CallAdapterFactory
Call<T>
- 定义的网络请求接口类
对于他们的主要功能上文已经解释过了,这里就不再进行解释,下面从最基本的网络请求来记录Retrofit
的运行流程。
四、运行流程
使用Retrofit
的时候首先要通过建造者模式创建一个实例对象,最终实例对象还是调用的Retrofit
的构造函数,所以这里看下构造函数即可知道有哪些参数:
Retrofit(okhttp3.Call.Factory callFactory,HttpUrl baseUrl,List<Converter.Factory> converterFactories,List<CallAdapter.Factory> callAdapterFactories,@Nullable Executor callbackExecutor,boolean validateEagerly) {this.callFactory = callFactory;this.baseUrl = baseUrl;this.converterFactories = converterFactories; // Copy+unmodifiable at call site.this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.this.callbackExecutor = callbackExecutor;this.validateEagerly = validateEagerly;}
这里简单说下这几个参数的含义:
callFactory
: 这个是okhttp
的一个接口,OkHttpClient
就是实现了这个接口,所以可以传入自定义的OkHttpClient
baseUrl
:故名思义,就是一个网络请求的基础域名converterFactories
:数据转换器集合callAdapterFactories
: 适配器集合callbackExecutor
: 一个用来调度返回值的回调的线程池,默认是主线程validateEagerly
: 这个用的不多,源码的意思是检查配置是否有效。通过源码知道定义的接口类是通过动态代理实现具体类的,但是里面的接口需要在调用的时候才进行检查,而这个参数的配置会提前进行检查,即不通过动态代理就可以执行。
当创建完Retrofit
的实例化对象后,需要通过Retrofit::create(final Class<T> service)
来创建接口的实例化对象。这里看下这个对象是如何创建的。
public final class Retrofit { ... private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();...public <T> T create(final Class<T> service) {validateServiceInterface(service);return (T)Proxy.newProxyInstance(service.getClassLoader(),new Class<?>[] {service},new InvocationHandler() {private final Platform platform = Platform.get();private final Object[] emptyArgs = new Object[0];@Overridepublic @Nullable 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);}args = args != null ? args : emptyArgs;return platform.isDefaultMethod(method)? platform.invokeDefaultMethod(method, service, proxy, args): loadServiceMethod(method).invoke(args);}});}...ServiceMethod<?> loadServiceMethod(Method method) {ServiceMethod<?> result = serviceMethodCache.get(method);if (result != null) return result;synchronized (serviceMethodCache) {result = serviceMethodCache.get(method);if (result == null) {result = ServiceMethod.parseAnnotations(this, method);serviceMethodCache.put(method, result);}}return result;}...
}
这里可以看到是使用动态代理的方式创建的,如果是系统默认函数就执行默认函数,如果是自己写的,就执行ServiceMethod<?> loadServiceMethod(Method method)
函数。然后可以看到通过ServiceMethod.parseAnnotations(this, method);
得到结果,然后添加进缓存里面去。这里看下这个写法:
abstract class ServiceMethod<T> {static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);Type returnType = method.getGenericReturnType();if (Utils.hasUnresolvableType(returnType)) {throw methodError(method,"Method return type must not include a type variable or wildcard: %s",returnType);}if (returnType == void.class) {throw methodError(method, "Service methods cannot return void.");}return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);}abstract @Nullable T invoke(Object[] args);
}
这里拿到相关方法后进行解析注解然后得到相对应的实体,然后在动态代理里面调用loadServiceMethod(method).invoke(args);
的invoke(args)
函数就是这里面的函数。看下具体实现。
abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {...@Overridefinal @Nullable ReturnT invoke(Object[] args) {Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);return adapt(call, args);}...
}
通过这里就知道在具体实现的适配器里面将数据返回,这个数据结构类型由具体的适配器进行构造。默认的就返回默认的Call
对象,RxJava就返回Observer<T>
对象
五、参考链接
- Retrofit
- 设计模式-代理模式:
- OkHttp原理
- restful接口和普通接口有啥区别_RESTful接口
- Retrofit 2.0中的validateEagerly()方法(beta 2)
Retrofit原理相关推荐
- Retrofit 原理解析
Retrofit 是什么? * Retrofit adapts a Java interface to HTTP calls by using annotations on the declared ...
- Retrofit原理分析
Retrofit原理分析 温故而知新 还记得retrofit的使用方法嘛,下面我们来回顾一下 接口定义 public interface GitHubService {@GET("users ...
- Retrofit 原理篇
1.Retrofit 实现原理 Retrofit 通过 java 接口以及注解来描述网络请求,并用动态代理的方式生成网络请求的 request,然后通过 client 调用相应的网络框架(默认 okh ...
- Retrofit原理学习总结
Retrofit 网络框架的原理在面试过程中经常被问道,笔者希望通过总结文字+流程图的方式来归纳Retrofit的原理.这篇也是OKHttp原理学习总结_我不勤奋v的博客-CSDN博客 的兄弟篇. 什 ...
- retrofit原理面试,2021最新百度、头条等公司Android社招面试题目,含答案解析
基本情况 硕士生,Android开发岗 此文主要是2021年初春招实习的面试和正式校招面试经验汇总,最终校招拿到了腾讯,百度,美团,网易等offer 主要包括阿里4面,腾讯8面,字节3面,百度3面,美 ...
- Jetpack Compose 初体验(上),retrofit原理面试
声明 Typography 对象,然后给 Text 添加 style 属性,来控制文字的样式. @Preview(showBackground = true) @Composable fun Vert ...
- Android进阶:七、Retrofit2.0原理解析之最简流程【上】
retrofit 已经流行很久了,它是Square开源的一款优秀的网络框架,这个框架对okhttp进行了封装,让我们使用okhttp做网路请求更加简单.但是光学会使用只是让我们多了一个技能,学习其源码 ...
- Android 注解Annotation及在流行框架中使用的原理
前言 Annotation--注解,JDK1.5新增加的功能.它能够添加到 Java 源代码的语法元数据.类.方法.变量.参数.包都可以被注解,可用来将信息元数据与程序元素进行关联.目前很多开源库都使 ...
- 从源码处理一理Retrofit的异步网络请求如何把结果切换到主线程
前提,需要具备的知识点是:动态代理,反射,注解. 场景:某日面试的时候被问道,Retrofit异步网络请求是怎么把结果返回给主线程的? 答曰:具体原理不是很清楚,最后应该是通过handler把结果发送 ...
- 我们究竟还要学习哪些Android知识?附赠课程+题库
2021新的一年,开启新的征程,回顾2020,真是太"南"了. 从年初各大厂裁员,竟然成为一件理所应当的事情,到四月份 GitHub 上"996.ICU" 引起 ...
最新文章
- GitHub代码一键转VS Code:只需+1s
- docker desktop ubuntu镜像_资深专家都知道的顶级 Docker 命令!
- socket 读取 所有 数据 java_Java Socket 读取服务器端返回数据
- STM32串口9位数据,无奇偶校验
- 著名投资人Chris Dixon:计算的下一波浪潮是什么?
- javascript-基本数据类型和转换
- 三角形和矩形傅里叶变换_信号与系统:第三章傅立叶变换2.ppt
- mysql常规使用(建立,增删改查,视图索引)
- 使用createObject(createObjectEx)创建silverlight对象
- Affinity Publisher for Mac(桌面排版神器)中文版
- mPaas集成项目、新建mPaaS项目
- yolov3-tiny
- mac怎么验机,都应该查什么
- 计算2个GPS坐标的距离
- 5个人站队,每个人不在原位置有多少种站法
- RHCE-8-管理变量和事实/任务控制
- Cocoapods的安装 简单教程(有待完善)
- 另类的 ETL 工具 sed 进阶
- 2021前端几大UI主流框架排行榜
- Python 序列数据的One Hot编码
热门文章
- 基于ECharts数据可视化案例--世界疫情实时展示
- java的package怎么用_Java包(Package)的详细用法(转)
- python xmind_Python 使用Python操作xmind文件
- 高考作文《细雨闲花》
- 如何理解P和NP问题
- 基于51单片机的带方位指示的自行车码表proteus仿真原理图PCB
- ssh弱口令暴力破解
- php验证qq,正则表达式验证qq号码是否输入正确
- 宿主机无法访问虚拟机web服务器,宿主机无法访问虚拟机中的docker容器怎么办_网站服务器运行维护,宿主机,虚拟机,docker...
- 地图上如何量方位角_经纬度计算距离和方位角