文章目录

  • 一、前言
  • 二、简单使用
  • 三、整体结构
  • 四、运行流程
  • 五、参考链接

一、前言

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有很多不同的地方:

  1. 网络请求采用RESTful风格和注解的方式进行配置。这种类似于配置文件式的写法使网络请求更好的维护
  2. 在进行网络请求中不像OkHttp那样涉及到其他部分,比如Request。这里都可以使用Retrofit创建的对象进行链式调用进行请求。这是一种基于装饰模式的写法(跟建造者模式不是一回事,区别在于一个是根据多个参数不一样进行动态配置)。
  3. 在创建过程中可以通过配置ConverterFactory进行数据转换。因为有时候传入的数据格式不支持,比如传入一个对象,这时候可以使用转换器转换成字符串,或者将一个字符串在返回的时候转换为一个对象。
  4. 在创建对象的时候通过配置CallAdapterFactoryOkHttpCall对象进行适配。在OkHttpCall是用来对RequestResponse进行处理的。这里可以看上述接口定义了两个不同的返回值,一个是Call<String>,另外一个是RxJava的Observable<String>。使用RxJava的话就可以调用不同的特性,这里就是使用CallAdapterFactory进行转换的。也可以转换成kotlin这些使用方式。Retrofit通过重新处理Call将返回值根据实现的不同的CallAdapterFactory做不同的转换,提高了强大的拓展性。
  5. 可以看到上文的响应值里面直接输出了Toast。要知道请求是子线程的,Toast显示是在主线程的,所以这里自己做了线程切换。也是一个很大的不同点。这个线程切换是在Retrofit默认的DefaultCallAdapterFactory中做的,其它适配器里面没写的话是没有线程切换的。
  6. 还有一个重要的不同点从使用上看的话不好直接看出来,那就是定义接口的实例对象都被缓存起来了,防止多次调用同一个对象都去创建新的接口对象,其它的对象也有类似的操作。这里减少了部分内存占用,提高了部分内存性能(因为这个缓存是定义在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>对象

五、参考链接

  1. Retrofit
  2. 设计模式-代理模式:
  3. OkHttp原理
  4. restful接口和普通接口有啥区别_RESTful接口
  5. Retrofit 2.0中的validateEagerly()方法(beta 2)

Retrofit原理相关推荐

  1. Retrofit 原理解析

    Retrofit 是什么? * Retrofit adapts a Java interface to HTTP calls by using annotations on the declared ...

  2. Retrofit原理分析

    Retrofit原理分析 温故而知新 还记得retrofit的使用方法嘛,下面我们来回顾一下 接口定义 public interface GitHubService {@GET("users ...

  3. Retrofit 原理篇

    1.Retrofit 实现原理 Retrofit 通过 java 接口以及注解来描述网络请求,并用动态代理的方式生成网络请求的 request,然后通过 client 调用相应的网络框架(默认 okh ...

  4. Retrofit原理学习总结

    Retrofit 网络框架的原理在面试过程中经常被问道,笔者希望通过总结文字+流程图的方式来归纳Retrofit的原理.这篇也是OKHttp原理学习总结_我不勤奋v的博客-CSDN博客 的兄弟篇. 什 ...

  5. retrofit原理面试,2021最新百度、头条等公司Android社招面试题目,含答案解析

    基本情况 硕士生,Android开发岗 此文主要是2021年初春招实习的面试和正式校招面试经验汇总,最终校招拿到了腾讯,百度,美团,网易等offer 主要包括阿里4面,腾讯8面,字节3面,百度3面,美 ...

  6. Jetpack Compose 初体验(上),retrofit原理面试

    声明 Typography 对象,然后给 Text 添加 style 属性,来控制文字的样式. @Preview(showBackground = true) @Composable fun Vert ...

  7. Android进阶:七、Retrofit2.0原理解析之最简流程【上】

    retrofit 已经流行很久了,它是Square开源的一款优秀的网络框架,这个框架对okhttp进行了封装,让我们使用okhttp做网路请求更加简单.但是光学会使用只是让我们多了一个技能,学习其源码 ...

  8. Android 注解Annotation及在流行框架中使用的原理

    前言 Annotation--注解,JDK1.5新增加的功能.它能够添加到 Java 源代码的语法元数据.类.方法.变量.参数.包都可以被注解,可用来将信息元数据与程序元素进行关联.目前很多开源库都使 ...

  9. 从源码处理一理Retrofit的异步网络请求如何把结果切换到主线程

    前提,需要具备的知识点是:动态代理,反射,注解. 场景:某日面试的时候被问道,Retrofit异步网络请求是怎么把结果返回给主线程的? 答曰:具体原理不是很清楚,最后应该是通过handler把结果发送 ...

  10. 我们究竟还要学习哪些Android知识?附赠课程+题库

    2021新的一年,开启新的征程,回顾2020,真是太"南"了. 从年初各大厂裁员,竟然成为一件理所应当的事情,到四月份 GitHub 上"996.ICU" 引起 ...

最新文章

  1. GitHub代码一键转VS Code:只需+1s
  2. docker desktop ubuntu镜像_资深专家都知道的顶级 Docker 命令!
  3. socket 读取 所有 数据 java_Java Socket 读取服务器端返回数据
  4. STM32串口9位数据,无奇偶校验
  5. 著名投资人Chris Dixon:计算的下一波浪潮是什么?
  6. javascript-基本数据类型和转换
  7. 三角形和矩形傅里叶变换_信号与系统:第三章傅立叶变换2.ppt
  8. mysql常规使用(建立,增删改查,视图索引)
  9. 使用createObject(createObjectEx)创建silverlight对象
  10. Affinity Publisher for Mac(桌面排版神器)中文版
  11. mPaas集成项目、新建mPaaS项目
  12. yolov3-tiny
  13. mac怎么验机,都应该查什么
  14. 计算2个GPS坐标的距离
  15. 5个人站队,每个人不在原位置有多少种站法
  16. RHCE-8-管理变量和事实/任务控制
  17. Cocoapods的安装 简单教程(有待完善)
  18. 另类的 ETL 工具 sed 进阶
  19. 2021前端几大UI主流框架排行榜
  20. Python 序列数据的One Hot编码

热门文章

  1. 基于ECharts数据可视化案例--世界疫情实时展示
  2. java的package怎么用_Java包(Package)的详细用法(转)
  3. python xmind_Python 使用Python操作xmind文件
  4. 高考作文《细雨闲花》
  5. 如何理解P和NP问题
  6. 基于51单片机的带方位指示的自行车码表proteus仿真原理图PCB
  7. ssh弱口令暴力破解
  8. php验证qq,正则表达式验证qq号码是否输入正确
  9. 宿主机无法访问虚拟机web服务器,宿主机无法访问虚拟机中的docker容器怎么办_网站服务器运行维护,宿主机,虚拟机,docker...
  10. 地图上如何量方位角_经纬度计算距离和方位角