解决Retrofit多BaseUrl及运行时动态改变BaseUrl(二)

原文地址: https://www.jianshu.com/p/35a8959c2f86

前言

我在之前的文章 《解决Retrofit多BaseUrl及运行时动态改变BaseUrl》 中,介绍了市面上能够解决此类问题的 4 个常见的解决方案,并开源了自己经过优化后的解决方案 RetrofitUrlManager,现在再为大家带来此系列的第二篇文章,这篇文章主要介绍 RetrofitUrlManager 针对 BaseUrl 替换逻辑的重大升级,因为这个升级对于 RetrofitUrlManager 足够重要,将使 RetrofitUrlManager 能够从容应对更多复杂的需求,所以单独写一篇文章让更多的人能够知道

Github : 您的 Star 是我坚持的动力 ✊

为什么不使用多 Retrofit 实例的方案?

在上篇文章 《解决Retrofit多BaseUrl及运行时动态改变BaseUrl》 中,4 种方案的特点和不足我都描述的很清楚,建议没看过这篇文章的可以去看看这篇文章,扩宽知识面,在后面的时间里经常有人问我为什么不使用多 Retrofit 实例的方案,多个 Retrofit 实例看起来并不会占用多少资源啊?

在回答之前为了让看这篇文章的人能了解我在说什么,所以我再粘贴下 上篇文章 中关于这个方案的部分描述

民间常用解决方案:
之前也看过很多开源的聚合类 App 源码, 像一些整合 知乎、 豆瓣、 Gank 等多个平台数据的 App, 因为各自平台的域名不同, 所以大多数这类 App 会给每个平台都各自创建一个 Retrofit 对象, 即不同的 BaseUrl 使用不同的 Retrofit 对象来创建 ApiService 进行请求, 这样只要新增一个不同的 BaseUrl, 那就需要重新创建一个新的 Retrofit 对象

我在这篇文章中重新回答下这个问题,为每个不同的 BaseUrl 都创建一个其他配置属性都一模一样的 Retrofit 实例不止会造成资源的浪费,还会造成接口管理成本的增加,这个才是最重要的一点, 举个例

我们平时项目中所有的 ApiService 都是使用同一个 Retrofit 实例的 Retrofit#create(ApiService) 方法进行实例化后开始接口的请求

但是当项目中出现多个 Retrofit 实例后,我们在开发中不光要区分哪些接口使用哪个 ApiService,还要区分哪些 ApiService 需要使用哪个 Retrofit 实例进行实例化,如果 ApiService 使用错误的 Retrofit 实例进行实例化,那这个 ApiService 的所有接口请求都注定完全失败

越复杂的项目,开发人数越多的项目,出错的风险就越大,并且扩展性也在大打折扣,后面一有变更将会十分痛苦,随着项目中接口的增加,以及 Retrofit 实例的增加 (BaseUrl 的增加),这个管理成本会成几何倍的增加

使用多 Retrofit 实例的方案前期投入成本过高,可能会影响之前项目管理接口的方式,某些封装过 Retrofit 的项目,也可能需要大改,对于老项目的接入不利,而使用 RetrofitUrlManager 不仅可以满足多 BaseUrl 及运行时动态改变 BaseUrl 的需求,还具有热插拔以及低侵入性的特点,在使用过程中将不会影响到之前的接口管理方式和使用方式,还具有极强的扩展性,可应对后面陆续增加的极其复杂的 BaseUrl 替换需求

升级之前的 RetrofitUrlManager 的问题

此次升级之前的 RetrofitUrlManager 版本,只是将 上篇文章 的思想完全实现,有了整个框架的基础,但是在动态替换 BaseUrl 方面还不够强大,最被大家吐槽的就是只能替换 BaseUrl 的域名

比如一个需要替换 BaseUrlUrl 地址为 "https:www.google.com/api/v2",其中 "https:www.google.com/api" 是我们传给 RetrofitBaseUrl,这时我们使用 RetrofitUrlManager 框架,想把 BaseUrl 替换成 "https:www.github.com",我们期望的替换后的 URL 地址是 "https:www.github.com/v2",但使用框架替换后的实际 URL 地址是 "https:www.github.com/api/v2", "/api" 作为 BaseUrl 的一部分并没有被新的 BaseUrl 替换掉,只是替换了 BaseUrl 中的域名

RetrofitUrlManager 是如何改善的

改善之前先要先分析为什么会这样?因为 RetrofitUrlManager 框架在拦截器中拦截到的 URL 地址是 Retrofit 已经把 BaseUrl 和接口注解中的相对路径合并后得到的最终路径地址,所以框架并不知道您传给 RetrofitBaseUrl 除了域名外还包含后面的 "/api",框架不知道 BaseUrl 的具体值,所以框架只会默认所有的 BaseUrl 都只含有域名,所以也就只能替换域名

高级模式

想要解决此类问题也很简单,告诉 RetrofitUrlManager 框架您传给 RetrofitBaseUrl 具体值即可,所以框架升级后增加了 RetrofitUrlManager#startAdvancedModel(String) 方法,在 App 初始化时将您传给 RetrofitBaseUrl 同样传给此方法,即可开启高级模式,高级模式即可替换拥有多个 pathSegmentsBaseUrl,不再局限于只能替换域名

什么是 pathSegment?

"https://www.github.com/wiki/part?name=jess" 中,其中的 "/wiki""/part" 就是 pathSegment, PathSize 就是 pathSegment 的个数

这个 URL 地址的 PathSize 就是 2, 第一个 pathSegment"/wiki",第二个 pathSegment"/part",可以粗略的理解为域名后面跟了几个 "/" PathSize 就是几

高级模式的替换规则

  1. URL 地址为 "https://www.github.com/wiki/part",您在 App 初始化时传入 RetrofitUrlManager#startAdvancedModel(String)BaseUrl"https://www.github.com/wiki",您想替换成的 BaseUrl 地址是 "https://www.google.com/api",经过框架替换后生成的最终 URL 地址为 "http://www.google.com/api/part"

  2. URL 地址为 "https://www.github.com/wiki/part",您在 App 初始化时传入 RetrofitUrlManager#startAdvancedModel(String)BaseUrl"https://www.github.com/wiki",您想替换成的 BaseUrl 地址是 "https://www.google.com",经过框架替换后生成的最终 URL 地址为 "http://www.google.com/part"

  3. URL 地址为 "https://www.github.com/wiki/part", 您在 App 初始化时传入 RetrofitUrlManager#startAdvancedModel(String)BaseUrl"https://www.github.com",您想替换成的 BaseUrl 地址是 "https://www.google.com/api",经过框架替换后生成的最终 URL 地址为 "http://www.google.com/api/wiki/part"

超级模式

超级模式是高级模式的加强版,优先级高于高级模式,按理说高级模式就能满足开发中的大部分需求,那什么又是超级模式呢?那就要先来说说高级模式了

高级模式的原理

在高级模式中您需要在 App 初始化时将您传给 RetrofitBaseUrl 同样传给 RetrofitUrlManager#startAdvancedModel(String) 一份,用以开启高级模式,成功开启高级模式后,这个传给 RetrofitUrlManager#startAdvancedModel(String)BaseUrl 就会作为框架替换 BaseUrl 的基准

什么叫作基准呢? 用此 BaseUrl 开启高级模式,并不意味着框架就只能替换 域名"www.github.com" 前两个 pathSegments"/wiki/part"URL,只要拥有域名以及大于或等于两个 pathSegmentsURL 都可以被框架替换,因此高级模式只会保存传入 RetrofitUrlManager#startAdvancedModel(String)BaseUrl 的格式 (保存 pathSegments 的个数),并不是保存具体的值

高级模式的局限

如果传给 RetrofitUrlManager#startAdvancedModel(String)BaseUrl"https://www.github.com/wiki/part" (PathSize = 2),框架就会将项目中所有 URL 中的 域名 以及 域名 后面的前两个 pathSegments 作为可被替换的 BaseUrl 整体,意味着框架只会将 URL 中的 域名 以及前两个 pathSegments 剪切并替换为您期望的 BaseUrl

这时服务器突然作出调整,项目中的一部分 URL 只需要将 "https://www.github.com/wiki" (PathSize = 1) 替换掉, 第二个 pathSegment "/part" 不再作为 BaseUrl 的一部分,不能被替换掉,必须要保留下来

这时项目中就出现了多个需要被替换的 BaseUrl 格式 (PathSize 不同),有些 URL 只需要替换 域名 以及前两个 pathSegments,有些又只需要替换 域名 以及前一个 pathSegments,但是在开启高级模式时,只保存了一个 BaseUrl 的格式,这时使用高级模式实现此需求就比较棘手

这个需求是一个比较变态的需求,可能很多人遇不上,但是我想让您知道当您遇上了也不要怕,因为 RetrofitUrlManager 的超级模式已经帮您考虑周全

超级模式的用法

超级模式与高级模式不同的是,开启超级模式并不需要调用 API,只须要在需要开启超级模式的 Url 尾部加上 RetrofitUrlManager#IDENTIFICATION_PATH_SIZE (#baseurl_path_size=) + PathSize,这样就明确的告诉了框架,在这个 URL 中需要被替换的 BaseUrl 含有几个 pathSegments,相当于每个 URL 都可以指定自己需要被替换的 BaseUrl 的格式,这样就比高级模式只能在 App 初始化时,指定一个全局的 BaseUrl 格式灵活得多,如果当您开启高级模式的同时也开启了超级模式,由于超级模式的优先级高于高级模式,所以只会执行超级模式

超级模式的替换规则

  1. URL 地址为 "https://www.github.com/wiki/part#baseurl_path_size=1""#baseurl_path_size=1" 表示其中 BaseUrl"https://www.github.com/wiki",您想替换成的 BaseUrl 地址是 "https://www.google.com/api",经过框架替换后生成的最终 URL 地址为 "http://www.google.com/api/part"

  2. URL 地址为 "https://www.github.com/wiki/part#baseurl_path_size=1""#baseurl_path_size=1" 表示其中 BaseUrl"https://www.github.com/wiki",您想替换成的 BaseUrl 地址是 "https://www.google.com",经过框架替换后生成的最终 URL 地址为 "http://www.google.com/part"

  3. URL 地址为 "https://www.github.com/wiki/part#baseurl_path_size=0""#baseurl_path_size=0" 表示其中 BaseUrl"https://www.github.com",您想替换成的 BaseUrl 地址是 "https://www.google.com/api",经过框架替换后生成的最终 URL 地址为 "http://www.google.com/api/wiki/part"

  4. URL 地址为 "https://www.github.com/wiki/part/issues/1#baseurl_path_size=3""#baseurl_path_size=3" 表示其中 BaseUrl"https://www.github.com/wiki/part/issues",您想替换成的 BaseUrl 地址是 "https://www.google.com/api",经过框架替换后生成的最终 URL 地址为 "http://www.google.com/api/1"

三种模式比较

在升级之前,框架就只有一个默认的普通模式 (只能替换域名),在升级之后新增了 高级模式超级模式,这两个模式让框架变得更加强大,在上面的内容中也详细的介绍了这两个模式,现在就来总结下这三个模式,让大家能够按照自己的需求选择出最适合的模式

替换 BaseUrl 的自由程度 (可扩展性)

普通模式 < 高级模式 < 超级模式

  • 普通模式: 只能替换域名

  • 高级模式: 只能替换在 RetrofitUrlManager#startAdvancedModel(String) 中传入的固定 BaseUrl 格式

  • 超级模式: 每个 URL 都可以随意指定可被替换的 BaseUrl 格式

使用上的复杂程度

普通模式 < 高级模式 < 超级模式

  • 普通模式: 无需做过多配置

  • 高级模式: 在 App 初始化时调用一次 RetrofitUrlManager#startAdvancedModel(String) 即可

  • 超级模式: 每个需要开启超级模式的 URL 尾部都需要加入 RetrofitUrlManager#IDENTIFICATION_PATH_SIZE (#baseurl_path_size=) + PathSize

总结

由此可见,自由度越强,使用上也越复杂,所以可以根据自己的需求选择对应的模式,并且也可以根据需求的变化随意升级或降级这三种模式

这次更新让 RetrofitUrlManager 的能力提升了一个档次,足以应对各种复杂的 BaseUrl 替换需求,正因为 RetrofitUrlManager 极强的扩展性,现在甚至可以做到,让服务器可以通过远程动态控制项目中的多个 BaseUrl

如果还有什么问题或者需求可以给我提 Issues,如果 RetrofitUrlManager 能够给您带来实质的帮助,也请不要吝啬您的 Star

公众号

搜索关注我的公众号 JessYan,一起学习进步,如果框架有更新,我也会在公众号上第一时间通知大家


Hello 我叫Jessyan,如果您喜欢我的文章,可以在以下平台关注我

-- The end

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,230评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,261评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,089评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,542评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,542评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,544评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,922评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,578评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,816评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,576评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,658评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,359评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,920评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,859评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,381评论 2 342

推荐阅读更多精彩内容