Android开发:从设计者角度看Retrofit原理

本文作者以设计者的角度深入剖析Retrofit的原理,探讨为何采用接口+注解形式请求,解释动态代理在Retrofit中的作用,并分析适配器模式和RESTful API的重要性。通过对Retrofit源码的解读,揭示了如何通过门面模式提高代码的易用性和可扩展性,以及动态代理在消除模板代码和遵循迪米特法则方面的优势。
摘要由CSDN通过智能技术生成

作者:Bezier

前言

通常我不喜欢去写分析源码类的文章,流水线式的分析 枯燥乏味,但读完Retrofit源码后让我有了改变这种想法的冲动~~

一般来讲读源码的好处有两点:

  • 熟悉代码设计流程,使用过程碰到问题可以更快速解决。说实话仅这一点无法激起我读源码的兴趣,毕竟以正确的姿态使用一个优秀的框架不应该出现这种问题。
  • 一个优秀的框架必须要保证易用性、扩展性,所以作者定会引入大量的思考进行设计,如若我们能吸收一二,那何尝不是与作者进行了一次心灵交互呢!

今天我将带着我的理解,尝试从设计者的角度分析Retrofit原理,相信你认真读完再加以思考,当再被面试官问Retrofit时你的答复或许会让他眼前一亮

提示:Retrofit基于2.9.0。文中贴的源码可能会有部分缺失,这是我刻意为之,目的在于筛选掉无用信息增强可读性

目录

  • 1. 什么是REST ful API?
  • 2. 为什么将请求设置为(接口+注解)形式?
  • 2.1. 迪米特法则和门面模式
  • 2.2. 为什么通过门面模式设计ApiService?
  • 3. 动态代理其实不是工具
  • 3.1. Retrofit构建
  • 3.2. 何为动态代理?
  • 3.3. 动态代理获取ApiService
  • 4. ReturnT、ResponseT做一次适配的意义何在?
  • 4.1 创建HttpServiceMethod
  • 4.2 如何管理callAdapter、responseConverter?
  • 4.3 发起请求

1. 什么是REST ful API?

一句话概括REST ful API:在我们使用HTTP协议做数据传输时应当遵守HTTP的规矩,包括请求方法、资源类型、Uri格式等等…

不久前在群里看到某小伙伴提出一个问题:“应后端要求需要在GET请求加入Body但Retrofit 中GET请求添加Body会报错,如何解决?” 一时间讨论的好不热闹,有让把Body塞到Header里的,有让自定义拦截器、也有人直接怂恿改源码…但问题的本质不是后端先违反规则在先吗?两个人打架总不能把挨打的抓起来吧。

俗话说无规矩不成方圆,面对以上这种情况应当让错误方去修改,因为所有人都知道GET没有Body,否则一旦其他人接手你的代码很容易被搞懵。

Retrofit对REST ful API的兼容做的很优秀,不符合规范直接给你报错,强行规范你的代码。所以你们公司正在使用REST ful API而Retrofit将是你的不二选择

2. 为什么将请求设置为(接口+注解)形式?

该小节为前置知识

2.1 迪米特法则和门面模式

迪米特法则:也称之为最小知道原则,即模块之间尽量减少不必要的依赖,即降低模块间的耦合性。

门面模式:基于迪米特法则拓展出来的一种设计模式,旨在将复杂的模块/系统访问入口控制的更加单一。举个例子:现要做一个获取图片功能,优先从本地缓存获取,没有缓存从网络获取随后再加入到本地缓存,假如不做任何处理,那每获取一张图片都要写一遍缓存逻辑,写的越多出错的可能就越高,其实调用者只是想获取一张图片而已,具体如何获取他不需要关心。此时可以通过门面模式将缓存功能做一个封装,只暴露出一个获取图片入口,这样调用者使用起来更加方便而且安全性更高。其实函数式编程也是门面模式的产物

2.2 为什么通过门面模式设计ApiService?

用Retrofit做一次请求大致流程如下:

interface ApiService {
    /**
     * 获取首页数据
     */
    @GET("/article/list/{page}/json")
    suspend fun getHomeList(@Path("page") pageNo: Int)
    : ApiResponse<ArticleBean>
}

//构建Retrofit
val retrofit = Retrofit.Builder().build()

//创建ApiService实例
val apiService =retrofit.create(ApiService::class.java)

//发起请求(这里用的是suspend会自动发起请求,Java中可通过返回的call请求)
apiService.getHomeList(1)

然后通过Retrofit创建ApiService类型实例调用对应方法即可发起请求。乍一看感觉很普通,但实际上Retrofit通过这种模式(门面模式)帮我们过滤掉了很多无用信息

tips:我们都知道Retrofit只不过是对OkHttp做了封装。

如果直接使用OkHttp,当在构造Request时要做很多繁琐的工作,最要命的是Request可能在多处被构造(ViewModel、Repository…),写的越分散出错时排查的难度就越高。而Retrofit通过注解的形式将Request需要的必要信息全依附在方法上(还是个抽象方法,尽量撇除一切多余信息),作为使用者只需要调用对应方法即可实现请求。至于如何解析、构造、发起请求 Retrofit内部会做处理,调用者不想也不需要知道,

所以Retrofit通过门面模式帮调用者屏蔽了一些无用信息,只暴露出唯一入口,让调用者更专注于业务开发。像我们常用的Room、GreenDao也使用了这种模式

3. 动态代理其实不是工具

看过很多Retrofit相关的文章,都喜欢上来就抛动态代理,关于为什么用只字不提,搞的Retrofit动态代理像是一个工具(框架)一样,殊不知它只是代理模式思想层面的一个产物而已。本小结会透过Retrofit看动态代理本质,帮你解除对它的误解

3.1 Retrofit构建

Retrofit构建如下所示:

Retrofit.Builder()
    .client(okHttpClient)
    .addConverterFactory(GsonConverterFactory.create())
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .baseUrl(ApiConstants.BASE_URL)
    .build()

很典型的构建者模式,可以配置OkHttp、Gson、RxJava等等,最后通过build()做构建操作,跟一下build()代码:

#Retrofit.class

public Retrofit build() {

        //1.CallAdapter工厂集合
        List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
        callAdapterFactories.
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值